@@ -204,6 +204,17 @@ class nok_resource : public http_resource {
204204 }
205205};
206206
207+ class static_resource : public http_resource {
208+ public:
209+ explicit static_resource (std::string r) : resp(std::move(r)) {}
210+
211+ shared_ptr<http_response> render_GET (const http_request&) {
212+ return shared_ptr<string_response>(new string_response (resp, 200 , " text/plain" ));
213+ }
214+
215+ std::string resp;
216+ };
217+
207218class no_response_resource : public http_resource {
208219 public:
209220 shared_ptr<http_response> render_GET (const http_request&) {
@@ -372,6 +383,70 @@ LT_BEGIN_AUTO_TEST(basic_suite, two_endpoints)
372383 }
373384LT_END_AUTO_TEST (two_endpoints)
374385
386+ LT_BEGIN_AUTO_TEST(basic_suite, duplicate_endpoints)
387+ ok_resource ok1, ok2;
388+ LT_CHECK_EQ (true , ws->register_resource (" OK" , &ok1));
389+
390+ // All of these collide and the registration fails
391+ LT_CHECK_EQ (false , ws->register_resource (" OK" , &ok2));
392+ LT_CHECK_EQ (false , ws->register_resource (" /OK" , &ok2));
393+ LT_CHECK_EQ (false , ws->register_resource (" /OK/" , &ok2));
394+ LT_CHECK_EQ (false , ws->register_resource (" OK/" , &ok2));
395+
396+ // Check how family interacts.
397+ LT_CHECK_EQ (false , ws->register_resource (" OK" , &ok2, true ));
398+
399+ // Check that switched case does the right thing, whatever that is here.
400+ #ifdef CASE_INSENSITIVE
401+ LT_CHECK_EQ (false , ws->register_resource (" ok" , &ok2));
402+ #else
403+ // TODO(etr): this should be true.
404+ // However, http_endpoint::operator< is always case-insensitive
405+ LT_CHECK_EQ (false , ws->register_resource (" ok" , &ok2));
406+ #endif
407+ LT_END_AUTO_TEST (duplicate_endpoints)
408+
409+ LT_BEGIN_AUTO_TEST(basic_suite, overlapping_endpoints)
410+ // Setup two different resources that can both match the same URL.
411+ static_resource ok1(" 1" ), ok2(" 2" );
412+ LT_CHECK_EQ (true , ws->register_resource (" /foo/{var|([a-z]+)}/" , &ok1));
413+ LT_CHECK_EQ (true , ws->register_resource (" /{var|([a-z]+)}/bar/" , &ok2));
414+
415+ curl_global_init (CURL_GLOBAL_ALL);
416+
417+ {
418+ string s;
419+ CURL *curl = curl_easy_init ();
420+ CURLcode res;
421+ curl_easy_setopt (curl, CURLOPT_URL, " localhost:8080/foo/bar/" );
422+ curl_easy_setopt (curl, CURLOPT_HTTPGET, 1L );
423+ curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, writefunc);
424+ curl_easy_setopt (curl, CURLOPT_WRITEDATA, &s);
425+ res = curl_easy_perform (curl);
426+ LT_ASSERT_EQ (res, 0 );
427+ LT_CHECK_EQ (s, " 2" ); // Not sure why regex wins, but it does...
428+ curl_easy_cleanup (curl);
429+ }
430+
431+ static_resource ok3 (" 3" );
432+ LT_CHECK_EQ (true , ws->register_resource (" /foo/bar/" , &ok3));
433+
434+ {
435+ // Check that an exact, non-RE match overrides both patterns.
436+ string s;
437+ CURL *curl = curl_easy_init ();
438+ CURLcode res;
439+ curl_easy_setopt (curl, CURLOPT_URL, " localhost:8080/foo/bar/" );
440+ curl_easy_setopt (curl, CURLOPT_HTTPGET, 1L );
441+ curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, writefunc);
442+ curl_easy_setopt (curl, CURLOPT_WRITEDATA, &s);
443+ res = curl_easy_perform (curl);
444+ LT_ASSERT_EQ (res, 0 );
445+ LT_CHECK_EQ (s, " 3" );
446+ curl_easy_cleanup (curl);
447+ }
448+ LT_END_AUTO_TEST (overlapping_endpoints)
449+
375450LT_BEGIN_AUTO_TEST(basic_suite, read_body)
376451 simple_resource resource;
377452 ws->register_resource (" base" , &resource);
@@ -1184,6 +1259,74 @@ LT_BEGIN_AUTO_TEST(basic_suite, url_with_regex_like_pieces)
11841259 curl_easy_cleanup (curl);
11851260LT_END_AUTO_TEST (url_with_regex_like_pieces)
11861261
1262+ LT_BEGIN_AUTO_TEST(basic_suite, non_family_url_with_regex_like_pieces)
1263+ ok_resource resource;
1264+ ws->register_resource (" /settings" , &resource);
1265+ curl_global_init (CURL_GLOBAL_ALL);
1266+
1267+ string s;
1268+ CURL *curl = curl_easy_init();
1269+ CURLcode res;
1270+ curl_easy_setopt (curl, CURLOPT_URL, " localhost:8080/settings/{}" );
1271+ curl_easy_setopt (curl, CURLOPT_HTTPGET, 1L );
1272+ curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, writefunc);
1273+ curl_easy_setopt (curl, CURLOPT_WRITEDATA, &s);
1274+ res = curl_easy_perform(curl);
1275+ LT_ASSERT_EQ (res, 0 );
1276+
1277+ int64_t http_code = 0 ;
1278+ curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE , &http_code);
1279+ LT_ASSERT_EQ (http_code, 404 );
1280+
1281+ curl_easy_cleanup (curl);
1282+ LT_END_AUTO_TEST (non_family_url_with_regex_like_pieces)
1283+
1284+ LT_BEGIN_AUTO_TEST(basic_suite, regex_url_exact_match)
1285+ ok_resource resource;
1286+ ws->register_resource (" /foo/{v|[a-z]}/bar" , &resource);
1287+ curl_global_init (CURL_GLOBAL_ALL);
1288+
1289+ {
1290+ string s;
1291+ CURL *curl = curl_easy_init ();
1292+ CURLcode res;
1293+ curl_easy_setopt (curl, CURLOPT_URL, " localhost:8080/foo/a/bar/" );
1294+ curl_easy_setopt (curl, CURLOPT_HTTPGET, 1L );
1295+ curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, writefunc);
1296+ curl_easy_setopt (curl, CURLOPT_WRITEDATA, &s);
1297+ res = curl_easy_perform (curl);
1298+ LT_ASSERT_EQ (res, 0 );
1299+
1300+ int64_t http_code = 0 ;
1301+ curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE , &http_code);
1302+ LT_ASSERT_EQ (http_code, 200 );
1303+
1304+ LT_CHECK_EQ (s, " OK" );
1305+ curl_easy_cleanup (curl);
1306+ }
1307+
1308+ {
1309+ string s;
1310+ CURL *curl = curl_easy_init ();
1311+ CURLcode res;
1312+ curl_easy_setopt (curl, CURLOPT_URL, " localhost:8080/foo/{v|[a-z]}/bar/" );
1313+ curl_easy_setopt (curl, CURLOPT_HTTPGET, 1L );
1314+ curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, writefunc);
1315+ curl_easy_setopt (curl, CURLOPT_WRITEDATA, &s);
1316+ res = curl_easy_perform (curl);
1317+ LT_ASSERT_EQ (res, 0 );
1318+
1319+ int64_t http_code = 0 ;
1320+ curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE , &http_code);
1321+ #if 0 // https://github.com/etr/libhttpserver/issues/308
1322+ LT_ASSERT_EQ(http_code, 404);
1323+ #else
1324+ LT_ASSERT_EQ (http_code, 200 );
1325+ #endif
1326+ curl_easy_cleanup (curl);
1327+ }
1328+ LT_END_AUTO_TEST (regex_url_exact_match)
1329+
11871330LT_BEGIN_AUTO_TEST(basic_suite, method_not_allowed_header)
11881331 simple_resource resource;
11891332 resource.disallow_all();
0 commit comments