@@ -35,6 +35,8 @@ void ResourceResolver::resolveNode(const std::string &method, const std::string
3535
3636 // Split URL in resource name and request params. Request params start after an optional '?'
3737 size_t reqparamIdx = url.find (' ?' );
38+ // Store this index to stop path parsing there
39+ size_t pathEnd = reqparamIdx != std::string::npos ? reqparamIdx : url.size ();
3840
3941 // If no '?' is contained in url, 0:npos will return the string as it is
4042 std::string resourceName = url.substr (0 , reqparamIdx);
@@ -72,92 +74,69 @@ void ResourceResolver::resolveNode(const std::string &method, const std::string
7274
7375
7476 // Check whether a resource matches
75- for (std::vector<HTTPNode*>::iterator node = _nodes->begin (); node != _nodes->end (); ++node) {
77+
78+ for (std::vector<HTTPNode*>::iterator itNode = _nodes->begin (); itNode != _nodes->end (); ++itNode) {
7679 params->resetPathParameters ();
77- if ((*node)->_nodeType ==nodeType) {
80+ HTTPNode *node = *itNode;
81+ if (node->_nodeType ==nodeType) {
7882 if (
7983 // For handler functions, check the method declared with the node
80- ((* node) ->_nodeType ==HANDLER_CALLBACK && ((ResourceNode*)* node)->_method == method) ||
84+ (node->_nodeType ==HANDLER_CALLBACK && ((ResourceNode*)node)->_method == method) ||
8185 // For websockets, the specification says that GET is the only choice
82- ((* node) ->_nodeType ==WEBSOCKET && method==" GET" )
86+ (node->_nodeType ==WEBSOCKET && method==" GET" )
8387 ) {
84- const std::string nodepath = ((*node)->_path );
85- if (!((*node)->hasPathParameter ())) {
86- HTTPS_LOGD (" Testing simple match on %s" , nodepath.c_str ());
87-
88- // Simple matching, the node does not contain any resource parameters
89- if (nodepath == resourceName) {
90- resolvedResource.setMatchingNode (*node);
91- HTTPS_LOGD (" It's a match! Path: %s" , nodepath.c_str ());
92- break ;
93- }
94- } else {
95- HTTPS_LOGD (" Testing parameter match on %s" , nodepath.c_str ());
96-
97- // Advanced matching, we need to align the /?/ parts.
98- bool didMatch = true ;
99- size_t urlIdx = 0 ; // Pointer how far the input url is processed
100- size_t nodeIdx = 0 ; // Pointer how far the node url is processed
101- for (int pIdx = 0 ; didMatch && pIdx < (*node)->getPathParamCount (); pIdx++) {
102- size_t pOffset = (*node)->getParamIdx (pIdx);
103-
104- // First step: Check static part
105- size_t staticLength = pOffset-nodeIdx;
106- if (nodepath.substr (nodeIdx, staticLength).compare (resourceName.substr (urlIdx, staticLength))!=0 ) {
107- // static part did not match
108- didMatch = false ;
109- HTTPS_LOGD (" No match on static part %d" , pIdx);
110- } else {
111- // static part did match, increase pointers
112- nodeIdx += staticLength + 1 ; // +1 to take care of the '*' placeholder.
113- urlIdx += staticLength; // The pointer should now point to the begin of the static part
114-
115- // Second step: Grab the parameter value
116- if (nodeIdx == nodepath.length ()) {
117- // Easy case: parse until end of string
118- params->setPathParameter (pIdx, urlDecode (resourceName.substr (urlIdx)));
119- } else {
120- // parse until first char after the placeholder
121- char terminatorChar = nodepath[nodeIdx];
122- size_t terminatorPosition = resourceName.find (terminatorChar, urlIdx);
123- if (terminatorPosition != std::string::npos) {
124- // We actually found the terminator
125- size_t dynamicLength = terminatorPosition-urlIdx;
126- params->setPathParameter (pIdx, urlDecode (resourceName.substr (urlIdx, dynamicLength)));
127- urlIdx = urlIdx + dynamicLength;
128- } else {
129- // We did not find the terminator
130- didMatch = false ;
131- HTTPS_LOGD (" No match on dynamic part %d" , pIdx);
132- }
133- }
134- } // static part did match
135- } // placeholder loop
136-
137- // If there is some final static part to process
138- if (didMatch && nodeIdx < nodepath.length ()) {
139- size_t staticLength = nodepath.length ()-nodeIdx;
140- if (nodepath.substr (nodeIdx, staticLength).compare (url.substr (urlIdx, staticLength))!=0 ) {
141- didMatch = false ;
142- HTTPS_LOGD (" No match, final static part did not match" );
88+ HTTPS_LOGD (" Testing route %s" , node->_path .c_str ());
89+ bool match = true ;
90+ size_t paramCount = node->getPathParamCount ();
91+ // indices in input and pattern
92+ size_t inputIdx = 0 , pathIdx = 0 ;
93+ HTTPS_LOGD (" (INIT) inputIdx: %d, pathIdx: %d, pathEnd: %d, path: %s, url: %s" ,
94+ inputIdx, pathIdx, pathEnd, node->_path .c_str (), url.c_str ());
95+
96+ for (size_t paramIdx = 0 ; match && paramIdx < paramCount; paramIdx += 1 ) {
97+ HTTPS_LOGD (" (LOOP) inputIdx: %d, pathIdx: %d, pathEnd: %d, path: %s, url: %s" ,
98+ inputIdx, pathIdx, pathEnd, node->_path .c_str (), url.c_str ());
99+ // Test static path before the parameter
100+ size_t paramPos = node->getParamIdx (paramIdx);
101+ size_t staticLength = paramPos - pathIdx;
102+ match &= url.substr (inputIdx, staticLength) == node->_path .substr (pathIdx, staticLength);
103+ inputIdx += staticLength;
104+ pathIdx += staticLength;
105+
106+ // Extract parameter value
107+ if (match) {
108+ size_t paramEnd = url.find (' /' , inputIdx);
109+ if (paramEnd == std::string::npos && inputIdx <= pathEnd) {
110+ // Consume the remaining input (might be "" for the last param)
111+ paramEnd = pathEnd;
112+ }
113+ if (paramEnd != std::string::npos) {
114+ size_t paramLength = paramEnd - inputIdx;
115+ params->setPathParameter (paramIdx, urlDecode (url.substr (inputIdx, paramLength)));
116+ pathIdx += 1 ;
117+ inputIdx += paramLength;
143118 } else {
144- urlIdx += staticLength;
145- // If there is some string remaining in the url that did not match
146- if (urlIdx < resourceName.length ()) {
147- didMatch = false ;
148- HTTPS_LOGD (" No match, URL is longer than final static part" );
149- }
119+ match = false ;
120+ HTTPS_LOGD (" (LOOP) No match on param part" );
150121 }
122+ } else {
123+ HTTPS_LOGD (" (LOOP) No match on static part" );
151124 }
152-
153- // Every check worked, so the full url matches and the params are set
154- if (didMatch) {
155- resolvedResource.setMatchingNode (*node);
156- HTTPS_LOGD (" It's a match!" );
157- break ;
158- }
159-
160- } // static/dynamic url
125+ }
126+ HTTPS_LOGD (" (STTC) inputIdx: %d, pathIdx: %d, pathEnd: %d, path: %s, url: %s" ,
127+ inputIdx, pathIdx, pathEnd, node->_path .c_str (), url.c_str ());
128+ // Test static path after the parameter (up to pathEnd)
129+ if (match) {
130+ match = url.substr (inputIdx, pathEnd - inputIdx)==node->_path .substr (pathIdx);
131+ }
132+ HTTPS_LOGD (" (END ) inputIdx: %d, pathIdx: %d, pathEnd: %d, path: %s, url: %s" ,
133+ inputIdx, pathIdx, pathEnd, node->_path .c_str (), url.c_str ());
134+
135+ if (match) {
136+ resolvedResource.setMatchingNode (node);
137+ HTTPS_LOGD (" It's a match!" );
138+ break ;
139+ }
161140 } // method check
162141 } // node type check
163142 } // resource node for loop
0 commit comments