Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix uwsgi_regexp_match() with pcre2 and corresponding unittest #2636

Merged
merged 4 commits into from
May 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 30 additions & 14 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,38 @@ on:
branches: [ master, uwsgi-2.0 ]

jobs:
python:

unittest:
runs-on: ubuntu-20.04
steps:
- name: Install dependencies
run: |
sudo apt update -qq
sudo apt install --no-install-recommends -qqyf \
libpcre2-dev libjansson-dev libcap2-dev \
check
- uses: actions/checkout@v4
- name: Run unit tests
run: make unittests

test:
runs-on: ubuntu-20.04
steps:
- name: Install dependencies
run: |
sudo apt update -qq
sudo apt install --no-install-recommends -qqyf \
libpcre2-dev libjansson-dev libcap2-dev
- uses: actions/checkout@v4
- name: Run integration tests
run: make all tests

python:
runs-on: ubuntu-20.04
strategy:
matrix:
python-version: ["2.7", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
test-suite: [unittest, python, deadlocks]
test-suite: [python, deadlocks]
steps:
- name: Add deadnakes ppa
run: sudo add-apt-repository ppa:deadsnakes/ppa -y
Expand All @@ -22,34 +47,27 @@ jobs:
sudo apt update -qq
sudo apt install --no-install-recommends -qqyf python${{ matrix.python-version }}-dev \
libpcre2-dev libjansson-dev libcap2-dev \
curl check
curl
- name: Install distutils
if: contains(fromJson('["3.6","3.7","3.8","3.9","3.10","3.11","3.12"]'), matrix.python-version)
run: |
sudo apt install --no-install-recommends -qqyf python${{ matrix.python-version }}-distutils \
- uses: actions/checkout@v4
- name: Run unit tests
if: matrix.test-suite == 'unittest'
run: make tests
- name: Build uWSGI binary
if: matrix.test-suite != 'unittest'
run: make
- name: Build python${{ matrix.python-version }} plugin
if: matrix.test-suite != 'unittest'
run: |
PYTHON_VERSION=${{ matrix.python-version }}
PYTHON_VERSION=python${PYTHON_VERSION//.}
/usr/bin/python${{ matrix.python-version }} -V
/usr/bin/python${{ matrix.python-version }} uwsgiconfig.py --plugin plugins/python base $PYTHON_VERSION
- name: run smoke tests
if: matrix.test-suite != 'unittest'
run: |
PYTHON_VERSION=${{ matrix.python-version }}
PYTHON_VERSION=python${PYTHON_VERSION//.}
./tests/gh-${{ matrix.test-suite }}.sh ${PYTHON_VERSION}
rack:

runs-on: ubuntu-20.04
strategy:
matrix:
Expand All @@ -59,11 +77,9 @@ jobs:
run: |
sudo apt update -qq
sudo apt install --no-install-recommends -qqyf python3-dev \
libpcre3-dev libjansson-dev libcap2-dev ruby2.7-dev \
curl check
libpcre2-dev libjansson-dev libcap2-dev ruby2.7-dev \
curl
- uses: actions/checkout@v4
- name: Run unit tests
run: make tests
- name: Build uWSGI binary
run: make
- name: Build rack plugin
Expand Down
8 changes: 6 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,20 @@ all:

clean:
$(PYTHON) uwsgiconfig.py --clean
cd unittest && make clean

check:
$(PYTHON) uwsgiconfig.py --check

plugin.%:
$(PYTHON) uwsgiconfig.py --plugin plugins/$* $(PROFILE)

tests:
unittests:
$(PYTHON) uwsgiconfig.py --build unittest
cd check && make && make test
cd unittest && make test

tests:
$(PYTHON) t/runner

%:
$(PYTHON) uwsgiconfig.py --build $@
Expand Down
2 changes: 1 addition & 1 deletion core/regexp.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ int uwsgi_regexp_build(char *re, uwsgi_pcre ** pattern) {

int uwsgi_regexp_match(uwsgi_pcre *pattern, const char *subject, int length) {
#ifdef UWSGI_PCRE2
return pcre2_match(pattern, (const unsigned char *)subject, length, 0, 0, NULL, NULL);
return uwsgi_regexp_match_ovec(pattern, subject, length, NULL, 0);
#else
return pcre_exec((const pcre *) pattern->p, (const pcre_extra *) pattern->extra, subject, length, 0, 0, NULL, 0);
#endif
Expand Down
82 changes: 82 additions & 0 deletions t/runner
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#!/usr/bin/python3


import os
import requests
import signal
import socket
import subprocess
import time
import unittest


TESTS_DIR = os.path.dirname(__file__)
UWSGI_BINARY = os.getenv("UWSGI_BINARY", os.path.join(TESTS_DIR, "..", "uwsgi"))
UWSGI_ADDR = "127.0.0.1"
UWSGI_PORT = 8000
UWSGI_HTTP = f"{UWSGI_ADDR}:{UWSGI_PORT}"


class BaseTest:
"""
Container class to avoid base test being run
"""

class UwsgiServerTest(unittest.TestCase):
"""
Test case with a server instance available on a socket for requests
"""

@classmethod
def uwsgi_ready(cls):
try:
s = socket.socket()
s.connect(
(
UWSGI_ADDR,
UWSGI_PORT,
)
)
except socket.error:
return False
else:
return True
finally:
s.close()

@classmethod
def setUpClass(cls):
# launch server
cls.testserver = subprocess.Popen(
[UWSGI_BINARY, "--http-socket", UWSGI_HTTP] + cls.ARGS
)

# ensure server is ready
retries = 10
while not cls.uwsgi_ready() and retries > 0:
time.sleep(0.1)
retries = retries - 1
if retries == 0:
raise RuntimeError("uwsgi test server is not available")

@classmethod
def tearDownClass(cls):
cls.testserver.send_signal(signal.SIGTERM)
cls.testserver.wait()


class StaticTest(BaseTest.UwsgiServerTest):

ARGS = [
"--plugin",
"python3", # provide a request plugin if no embedded request plugin
os.path.join(TESTS_DIR, "static", "config.ini"),
]

def test_static_expires(self):
with requests.get(f"http://{UWSGI_HTTP}/foobar/config.ini") as r:
self.assertTrue("Expires" in r.headers)


if __name__ == "__main__":
unittest.main()
4 changes: 4 additions & 0 deletions t/static/config.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[uwsgi]
need-app = False
static-map = /foobar=t/static
static-expires-uri = ^/foobar/ 315360000
7 changes: 4 additions & 3 deletions check/Makefile → unittest/Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

CFLAGS = $(shell pkg-config --cflags check)
CFLAGS += -DUWSGI_PCRE2
LDFLAGS = $(shell pkg-config --libs check)
LDFLAGS += -ldl -lz
LDFLAGS += $(shell xml2-config --libs)
Expand All @@ -13,14 +14,14 @@ ifeq ($(UNAME_S),Linux)
endif


objects = check_core
objects = check_core check_regexp

all: $(objects)

$(objects): %: %.c
$(objects): %: %.c ../libuwsgi.a
$(CC) $(CFLAGS) -o $@ $< ../libuwsgi.a $(LDFLAGS)

test:
test: all
@for file in $(objects); do ./$$file; done

clean:
Expand Down
File renamed without changes.
86 changes: 86 additions & 0 deletions unittest/check_regexp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#include <check.h>
#include "../uwsgi.h"


START_TEST(test_uwsgi_regexp_match)
{
int result;
uwsgi_pcre *pattern_all;
uwsgi_pcre *pattern;

result = uwsgi_regexp_build(".*", &pattern_all);
ck_assert(result == 0);

result = uwsgi_regexp_match(pattern_all, "/fooba", 6);
ck_assert(result >= 0);

result = uwsgi_regexp_build("/foobar/.*", &pattern);
ck_assert(result == 0);

result = uwsgi_regexp_match(pattern, "/fooba", 6);
ck_assert(result < 0);

result = uwsgi_regexp_match(pattern, "/foobar/baz", 11);
ck_assert(result >= 0);

pcre2_code_free(pattern_all);
pcre2_code_free(pattern);
}
END_TEST

START_TEST(test_uwsgi_regexp_match_ovec)
{
int result;
uwsgi_pcre *pattern;
int *ovec = calloc((2+1)*2, sizeof(int));
char buf[20], sub[20];

result = uwsgi_regexp_build("^/foo/(.*)\\.jpg\\?([0-9]{2})", &pattern);
ck_assert(result == 0);
result = uwsgi_regexp_ovector(pattern);
ck_assert(result == 2);

result = uwsgi_regexp_match_ovec(pattern, "/fooba", 6, ovec, 2);
ck_assert(result < 0);

strcpy(buf, "/foo/bar.jpg?422");
result = uwsgi_regexp_match_ovec(pattern, buf, strlen(buf), ovec, 2);
ck_assert(result >= 0);
strncpy(sub, buf+ovec[0], ovec[1]-ovec[0]);
sub[ovec[1]-ovec[0]] = '\0';
ck_assert_str_eq(sub, "/foo/bar.jpg?42");
strncpy(sub, buf+ovec[2], ovec[3]-ovec[2]);
sub[ovec[3]-ovec[2]] = '\0';
ck_assert_str_eq(sub, "bar");
strncpy(sub, buf+ovec[4], ovec[5]-ovec[4]);
sub[ovec[5]-ovec[4]] = '\0';
ck_assert_str_eq(sub, "42");

strcpy(sub, uwsgi_regexp_apply_ovec(buf, strlen(buf), "key=$1.$2.jpg", 13, ovec, 2));
ck_assert_str_eq(sub, "key=bar.42.jpg");

pcre2_code_free(pattern);
free(ovec);
}
END_TEST

Suite *check_regexp(void)
{
Suite *s = suite_create("uwsgi regexp");
TCase *tc = tcase_create("regexp");

suite_add_tcase(s, tc);
tcase_add_test(tc, test_uwsgi_regexp_match);
tcase_add_test(tc, test_uwsgi_regexp_match_ovec);
return s;
}

int main(void)
{
int nf;
SRunner *r = srunner_create(check_regexp());
srunner_run_all(r, CK_NORMAL);
nf = srunner_ntests_failed(r);
srunner_free(r);
return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}