Skip to content

Commit b4653f4

Browse files
scopdevyte
authored andcommitted
Fix URL parameter decoding in web server (#3313)
* Make HTTP server test data easier to examine * Add HTTP server parameter tests containing & and = * Fix URL parameter decoding in web server The parameters string needs to be first split on & and =, and URL decoding on parts done after that. Otherwise URL encoded & and = within parameter names and values cause incorrect splitting.
1 parent 4ab89d0 commit b4653f4

File tree

3 files changed

+19
-23
lines changed

3 files changed

+19
-23
lines changed

libraries/ESP8266WebServer/src/Parsing.cpp

+2-6
Original file line numberDiff line numberDiff line change
@@ -184,13 +184,9 @@ bool ESP8266WebServer::_parseRequest(WiFiClient& client) {
184184
return false;
185185
}
186186
if (contentLength > 0) {
187-
if (searchStr != "") searchStr += '&';
188187
if(isEncoded){
189188
//url encoded form
190-
String decoded = urlDecode(plainBuf);
191-
size_t decodedLen = decoded.length();
192-
memcpy(plainBuf, decoded.c_str(), decodedLen);
193-
plainBuf[decodedLen] = 0;
189+
if (searchStr != "") searchStr += '&';
194190
searchStr += plainBuf;
195191
}
196192
_parseArguments(searchStr);
@@ -321,7 +317,7 @@ void ESP8266WebServer::_parseArguments(String data) {
321317
continue;
322318
}
323319
RequestArgument& arg = _currentArgs[iarg];
324-
arg.key = data.substring(pos, equal_sign_index);
320+
arg.key = urlDecode(data.substring(pos, equal_sign_index));
325321
arg.value = urlDecode(data.substring(equal_sign_index + 1, next_arg_index));
326322
#ifdef DEBUG_ESP_HTTP_SERVER
327323
DEBUG_OUTPUT.print("arg ");

tests/device/test_http_server/test_http_server.ino

+13-13
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,16 @@ TEST_CASE("HTTP GET Parameters", "[HTTPServer]")
3636
siteData = "";
3737
for (uint8_t i=0; i<server.args(); i++){
3838
if(i > 0)
39-
siteData += "&";
40-
siteData += server.argName(i) + "=" + server.arg(i);
39+
siteData += "\n";
40+
siteData += server.argName(i) + " = " + server.arg(i);
4141
}
4242
siteHits++;
4343
server.send(200, "text/plain", siteData);
4444
});
4545
uint32_t startTime = millis();
4646
while(siteHits == 0 && (millis() - startTime) < 10000)
4747
server.handleClient();
48-
REQUIRE(siteHits > 0 && siteData.equals("var1=val with spaces&var+=some%"));
48+
REQUIRE(siteHits > 0 && siteData.equals("var1 = val with spaces\nva=r+ = so&me%"));
4949
}
5050
}
5151

@@ -57,16 +57,16 @@ TEST_CASE("HTTP POST Parameters", "[HTTPServer]")
5757
siteData = "";
5858
for (uint8_t i=0; i<server.args(); i++){
5959
if(i > 0)
60-
siteData += "&";
61-
siteData += server.argName(i) + "=" + server.arg(i);
60+
siteData += "\n";
61+
siteData += server.argName(i) + " = " + server.arg(i);
6262
}
6363
siteHits++;
6464
server.send(200, "text/plain", siteData);
6565
});
6666
uint32_t startTime = millis();
6767
while(siteHits == 0 && (millis() - startTime) < 10000)
6868
server.handleClient();
69-
REQUIRE(siteHits > 0 && siteData.equals("var2=val with spaces"));
69+
REQUIRE(siteHits > 0 && siteData.equals("var2 = val with spaces"));
7070
}
7171
}
7272

@@ -78,16 +78,16 @@ TEST_CASE("HTTP GET+POST Parameters", "[HTTPServer]")
7878
siteData = "";
7979
for (uint8_t i=0; i<server.args(); i++){
8080
if(i > 0)
81-
siteData += "&";
82-
siteData += server.argName(i) + "=" + server.arg(i);
81+
siteData += "\n";
82+
siteData += server.argName(i) + " = " + server.arg(i);
8383
}
8484
siteHits++;
8585
server.send(200, "text/plain", siteData);
8686
});
8787
uint32_t startTime = millis();
8888
while(siteHits == 0 && (millis() - startTime) < 10000)
8989
server.handleClient();
90-
REQUIRE(siteHits > 0 && siteData.equals("var3=val with spaces&var+=some%"));
90+
REQUIRE(siteHits > 0 && siteData.equals("var3 = val with spaces\nva&r+ = so=me%"));
9191
}
9292
}
9393

@@ -98,8 +98,8 @@ TEST_CASE("HTTP Upload", "[HTTPServer]")
9898
server.on("/upload", HTTP_POST, [](){
9999
for (uint8_t i=0; i<server.args(); i++){
100100
if(i > 0)
101-
siteData += "&";
102-
siteData += server.argName(i) + "=" + server.arg(i);
101+
siteData += "\n";
102+
siteData += server.argName(i) + " = " + server.arg(i);
103103
}
104104
siteHits++;
105105
server.send(200, "text/plain", siteData);
@@ -110,13 +110,13 @@ TEST_CASE("HTTP Upload", "[HTTPServer]")
110110
} else if(upload.status == UPLOAD_FILE_END){
111111
siteData.concat(":");
112112
siteData.concat(String(upload.totalSize));
113-
siteData.concat("&");
113+
siteData.concat("\n");
114114
}
115115
});
116116
uint32_t startTime = millis();
117117
while(siteHits == 0 && (millis() - startTime) < 10000)
118118
server.handleClient();
119-
REQUIRE(siteHits > 0 && siteData.equals("test.txt:16&var4=val with spaces"));
119+
REQUIRE(siteHits > 0 && siteData.equals("test.txt:16\nvar4 = val with spaces"));
120120
}
121121
}
122122

tests/device/test_http_server/test_http_server.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def http_test(res, url, get=None, post=None):
2424
@setup('HTTP GET Parameters')
2525
def setup_http_get_params(e):
2626
def testRun():
27-
return http_test('var1=val with spaces&var+=some%', 'http://etd.local/get', {'var1' : 'val with spaces', 'var+' : 'some%'})
27+
return http_test('var1 = val with spaces\nva=r+ = so&me%', 'http://etd.local/get', {'var1' : 'val with spaces', 'va=r+' : 'so&me%'})
2828
Thread(target=testRun).start()
2929

3030
@teardown('HTTP GET Parameters')
@@ -34,7 +34,7 @@ def teardown_http_get_params(e):
3434
@setup('HTTP POST Parameters')
3535
def setup_http_post_params(e):
3636
def testRun():
37-
return http_test('var2=val with spaces', 'http://etd.local/post', None, {'var2' : 'val with spaces'})
37+
return http_test('var2 = val with spaces', 'http://etd.local/post', None, {'var2' : 'val with spaces'})
3838
Thread(target=testRun).start()
3939

4040
@teardown('HTTP POST Parameters')
@@ -44,7 +44,7 @@ def teardown_http_post_params(e):
4444
@setup('HTTP GET+POST Parameters')
4545
def setup_http_getpost_params(e):
4646
def testRun():
47-
return http_test('var3=val with spaces&var+=some%', 'http://etd.local/get_and_post', {'var3' : 'val with spaces'}, {'var+' : 'some%'})
47+
return http_test('var3 = val with spaces\nva&r+ = so=me%', 'http://etd.local/get_and_post', {'var3' : 'val with spaces'}, {'va&r+' : 'so=me%'})
4848
Thread(target=testRun).start()
4949

5050
@teardown('HTTP GET+POST Parameters')
@@ -63,7 +63,7 @@ def testRun():
6363
response = urllib2.urlopen(request, None, 2).read()
6464
except:
6565
return 1
66-
if response != 'test.txt:16&var4=val with spaces':
66+
if response != 'test.txt:16\nvar4 = val with spaces':
6767
return 1
6868
return 0
6969
Thread(target=testRun).start()

0 commit comments

Comments
 (0)