{"action":"closed","issue":{"url":"https://api.github.com/repos/civetweb/civetweb/issues/337","repository_url":"https://api.github.com/repos/civetweb/civetweb","labels_url":"https://api.github.com/repos/civetweb/civetweb/issues/337/labels{/name}","comments_url":"https://api.github.com/repos/civetweb/civetweb/issues/337/comments","events_url":"https://api.github.com/repos/civetweb/civetweb/issues/337/events","html_url":"https://github.com/civetweb/civetweb/issues/337","id":168659394,"number":337,"title":"Bugfix or better more correctness in civetweb.c get_request_handler","user":{"login":"hcp24","id":19992645,"avatar_url":"https://avatars.githubusercontent.com/u/19992645?v=3","gravatar_id":"","url":"https://api.github.com/users/hcp24","html_url":"https://github.com/hcp24","followers_url":"https://api.github.com/users/hcp24/followers","following_url":"https://api.github.com/users/hcp24/following{/other_user}","gists_url":"https://api.github.com/users/hcp24/gists{/gist_id}","starred_url":"https://api.github.com/users/hcp24/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hcp24/subscriptions","organizations_url":"https://api.github.com/users/hcp24/orgs","repos_url":"https://api.github.com/users/hcp24/repos","events_url":"https://api.github.com/users/hcp24/events{/privacy}","received_events_url":"https://api.github.com/users/hcp24/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":0,"created_at":"2016-08-01T14:28:23Z","updated_at":"2016-08-01T14:42:01Z","closed_at":"2016-08-01T14:42:01Z","body":"As i played with the authentication handlers i got following problem:\r\n(I using c++ so i have to translate to c).\r\n\r\nI put two auth handlers to the engine like this\r\n\r\nfirst : **mg_set_auth_handler**( context, _\"/secure/\"_, authHandler, h1);\r\nsecond: **mg_set_auth_handler**( context, _\"/sercure/more_secure/\"_, authHandler, h2);\r\n\r\nIf I call _\"http://server/secure/more_secure/somthing\"_ only the first auth handler _\"/sercure/\"_ was called but I expected the second one _\"/secure/more_secure/\"_ will be called.\r\nI did not tried any other sequences like \r\nfirst: **mg_set_auth_handler**(  context, _\"/sercure/more_secure/\"_, authHandler, h2);\r\nsecond: **mg_set_auth_handler**( context, _\"/sercure/\"_, authHandler, h1);\r\nIt works (conn->ctx->handlers is an unsorted single linked list).\r\nThe same is happens on all other handlers. With a little changes in the code it will be more robust\r\nagainst stupid developers like me.\r\nThe sequence of handler insertion should never be decided. \r\nIf I decode sequences in my mind I will do it from largest to smallest.\r\n\r\nI have two solutions:\r\n\r\n 1. sort the conn->ctx->handlers on insert and use uri_len from largest to smallest.\r\n    Then it will always match the nerest uri.  I prefer this variant. \r\n\r\n    Put this code at the end of mg_set_handler_type it works for me (I tested it a little bit but not extensive). It must replace the two last lines \r\n  *lastref = tmp_rh;\r\n  mg_unlock_context(ctx);\r\n(it is the #else way on #if 1)\r\n\r\n```\r\n#if 1 /* enable/disable work around */\r\n  if (ctx->handlers != NULL) {\r\n    struct mg_handler_info *rh1, *rhLast;\r\n    /* check for insert */\r\n    for (rh1 = ctx->handlers; rh1 != NULL; rh1 = rh1->next) {\r\n      if (rh1->uri_len > tmp_rh->uri_len) {\r\n        rhLast = rh1; /* save last (is not a double linked list) */\r\n      }\r\n      else {\r\n        /* position found */\r\n        tmp_rh->next = rh1;\r\n        if (rh1 == ctx->handlers)\r\n          ctx->handlers = tmp_rh;\r\n        else\r\n          rhLast->next = tmp_rh;\r\n        mg_unlock_context(ctx);\r\n        return;\r\n      }\r\n    }\r\n  }\r\n  /* no position found or first handler put on last */\r\n  *lastref = tmp_rh;\r\n  mg_unlock_context(ctx);\r\n#else\r\n  / * old variant */\r\n  *lastref = tmp_rh;\r\n  mg_unlock_context(ctx);\r\n#endif\r\n\r\n```    \r\n 2. change get_request_handler loop (it's easier ?? but cost more time)\r\n\r\n```\r\n       /* next try for a partial match, we will accept uri/something */\r\n        { /* create a block so c variables can be placed here */ \r\n          int found_len = 0; /* PF added initialize with 0 */\r\n          for (tmp_rh = conn->ctx->handlers; tmp_rh != NULL; tmp_rh = tmp_rh->next) {\r\n            if (tmp_rh->handler_type == handler_type) {\r\n              /*PF use only if tmp_rh->uri_len > found_len */\r\n              if ( tmp_rh->uri_len < urilen \r\n                   && tmp_rh->uri_len > found_len /* PF changes */\r\n                   && uri[tmp_rh->uri_len] == '/' && memcmp(tmp_rh->uri, uri, tmp_rh->uri_len) == 0) {\r\n                found_len = tmp_rh->uri_len;  /* PF set new len */\r\n                if (handler_type == WEBSOCKET_HANDLER) {\r\n                  *connect_handler = tmp_rh->connect_handler;\r\n                  *ready_handler = tmp_rh->ready_handler;\r\n                  *data_handler = tmp_rh->data_handler;\r\n                  *close_handler = tmp_rh->close_handler;\r\n                } else if (handler_type == REQUEST_HANDLER) {\r\n                  *handler = tmp_rh->handler;\r\n                } else { /* AUTH_HANDLER */\r\n                  *auth_handler = tmp_rh->auth_handler;\r\n                }\r\n                *cbdata = tmp_rh->cbdata; /* some found */\r\n              }\r\n            }\r\n          }\r\n          if (*cbdata && (found_len > 0)) {\r\n            mg_unlock_context(conn->ctx);\r\n            return 1; /* found */\r\n          }\r\n        } /* end block */\r\n\r\n```\r\nExcuse my bad english I'm a stupid German. \r\nI hope it will be helpful.\r\nbest regards\r\n"}}
{"actor":{"display_login":"hcp24"}}