36
36
#define DEBUG_OUTPUT Serial
37
37
#endif
38
38
39
- const char * AUTHORIZATION_HEADER = " Authorization" ;
39
+ // const char * AUTHORIZATION_HEADER = "Authorization";
40
+ static const char AUTHORIZATION_HEADER[] PROGMEM = " Authorization" ;
41
+ static const char qop_auth[] PROGMEM = " qop=auth" ;
42
+ static const char WWW_Authenticate[] PROGMEM = " WWW-Authenticate" ;
43
+ static const char colon[] PROGMEM = " :" ;
44
+ static const char Content_Length[] PROGMEM = " Content-Length" ;
45
+
40
46
41
47
ESP8266WebServer::ESP8266WebServer (IPAddress addr, int port)
42
48
: _server(addr, port)
43
49
, _currentMethod(HTTP_ANY)
44
50
, _currentVersion(0 )
45
51
, _currentStatus(HC_NONE)
46
52
, _statusChange(0 )
47
- , _currentHandler(0 )
48
- , _firstHandler(0 )
49
- , _lastHandler(0 )
53
+ , _currentHandler(nullptr )
54
+ , _firstHandler(nullptr )
55
+ , _lastHandler(nullptr )
50
56
, _currentArgCount(0 )
51
- , _currentArgs(0 )
57
+ , _currentArgs(nullptr )
52
58
, _headerKeysCount(0 )
53
- , _currentHeaders(0 )
59
+ , _currentHeaders(nullptr )
54
60
, _contentLength(0 )
55
61
, _chunked(false )
56
62
{
@@ -62,13 +68,13 @@ ESP8266WebServer::ESP8266WebServer(int port)
62
68
, _currentVersion(0 )
63
69
, _currentStatus(HC_NONE)
64
70
, _statusChange(0 )
65
- , _currentHandler(0 )
66
- , _firstHandler(0 )
67
- , _lastHandler(0 )
71
+ , _currentHandler(nullptr )
72
+ , _firstHandler(nullptr )
73
+ , _lastHandler(nullptr )
68
74
, _currentArgCount(0 )
69
- , _currentArgs(0 )
75
+ , _currentArgs(nullptr )
70
76
, _headerKeysCount(0 )
71
- , _currentHeaders(0 )
77
+ , _currentHeaders(nullptr )
72
78
, _contentLength(0 )
73
79
, _chunked(false )
74
80
{
@@ -88,145 +94,150 @@ ESP8266WebServer::~ESP8266WebServer() {
88
94
}
89
95
90
96
void ESP8266WebServer::begin () {
91
- _currentStatus = HC_NONE ;
97
+ close () ;
92
98
_server.begin ();
93
- if (!_headerKeysCount)
94
- collectHeaders (0 , 0 );
95
99
}
96
100
97
- String ESP8266WebServer::_exractParam (String& authReq,const String& param,const char delimit){
101
+ void ESP8266WebServer::begin (uint16_t port) {
102
+ close ();
103
+ _server.begin (port);
104
+ }
105
+
106
+ String ESP8266WebServer::_extractParam (String& authReq,const String& param,const char delimit){
98
107
int _begin = authReq.indexOf (param);
99
- if (_begin==-1 ) return " " ;
108
+ if (_begin==-1 )
109
+ return " " ;
100
110
return authReq.substring (_begin+param.length (),authReq.indexOf (delimit,_begin+param.length ()));
101
111
}
102
112
103
113
bool ESP8266WebServer::authenticate (const char * username, const char * password){
104
- if (hasHeader (AUTHORIZATION_HEADER)){
105
- String authReq = header (AUTHORIZATION_HEADER);
106
- if (authReq.startsWith (" Basic" )){
114
+ if (hasHeader (FPSTR ( AUTHORIZATION_HEADER))) {
115
+ String authReq = header (FPSTR ( AUTHORIZATION_HEADER) );
116
+ if (authReq.startsWith (F ( " Basic" ) )){
107
117
authReq = authReq.substring (6 );
108
118
authReq.trim ();
109
119
char toencodeLen = strlen (username)+strlen (password)+1 ;
110
120
char *toencode = new char [toencodeLen + 1 ];
111
121
if (toencode == NULL ){
112
- authReq = String () ;
122
+ authReq = " " ;
113
123
return false ;
114
124
}
115
125
char *encoded = new char [base64_encode_expected_len (toencodeLen)+1 ];
116
126
if (encoded == NULL ){
117
- authReq = String () ;
127
+ authReq = " " ;
118
128
delete[] toencode;
119
129
return false ;
120
130
}
121
131
sprintf (toencode, " %s:%s" , username, password);
122
132
if (base64_encode_chars (toencode, toencodeLen, encoded) > 0 && authReq.equalsConstantTime (encoded)) {
123
- authReq = String () ;
133
+ authReq = " " ;
124
134
delete[] toencode;
125
135
delete[] encoded;
126
136
return true ;
127
137
}
128
138
delete[] toencode;
129
139
delete[] encoded;
130
- }else if (authReq.startsWith (" Digest" )){
140
+ } else if (authReq.startsWith (F ( " Digest" ))) {
131
141
authReq = authReq.substring (7 );
132
142
#ifdef DEBUG_ESP_HTTP_SERVER
133
143
DEBUG_OUTPUT.println (authReq);
134
144
#endif
135
- String _username = _exractParam (authReq," username=\" " );
136
- if (( !_username.length ())|| _username!= String (username)){
137
- authReq = String () ;
145
+ String _username = _extractParam (authReq,F ( " username=\" " ) );
146
+ if (!_username.length () || _username != String (username)) {
147
+ authReq = " " ;
138
148
return false ;
139
149
}
140
150
// extracting required parameters for RFC 2069 simpler Digest
141
- String _realm = _exractParam (authReq," realm=\" " );
142
- String _nonce = _exractParam (authReq," nonce=\" " );
143
- String _uri = _exractParam (authReq," uri=\" " );
144
- String _response = _exractParam (authReq," response=\" " );
145
- String _opaque = _exractParam (authReq," opaque=\" " );
146
-
147
- if ((!_realm.length ())|| (!_nonce.length ())|| (!_uri.length ())|| (!_response.length ())|| (!_opaque.length ())){
148
- authReq = String () ;
151
+ String _realm = _extractParam (authReq, F ( " realm=\" " ) );
152
+ String _nonce = _extractParam (authReq, F ( " nonce=\" " ) );
153
+ String _uri = _extractParam (authReq, F ( " uri=\" " ) );
154
+ String _response = _extractParam (authReq, F ( " response=\" " ) );
155
+ String _opaque = _extractParam (authReq, F ( " opaque=\" " ) );
156
+
157
+ if ((!_realm.length ()) || (!_nonce.length ()) || (!_uri.length ()) || (!_response.length ()) || (!_opaque.length ())) {
158
+ authReq = " " ;
149
159
return false ;
150
160
}
151
- if ((_opaque!= _sopaque)|| (_nonce!= _snonce)|| (_realm!= _srealm)){
152
- authReq = String () ;
161
+ if ((_opaque != _sopaque) || (_nonce != _snonce) || (_realm != _srealm)) {
162
+ authReq = " " ;
153
163
return false ;
154
164
}
155
165
// parameters for the RFC 2617 newer Digest
156
166
String _nc,_cnonce;
157
- if (authReq.indexOf (" qop=auth " ) != -1 ){
158
- _nc = _exractParam (authReq," nc=" , ' ,' );
159
- _cnonce = _exractParam (authReq," cnonce=\" " );
167
+ if (authReq.indexOf (FPSTR (qop_auth)) != -1 ) {
168
+ _nc = _extractParam (authReq, F ( " nc=" ), ' ,' );
169
+ _cnonce = _extractParam (authReq, F ( " cnonce=\" " ) );
160
170
}
161
171
MD5Builder md5;
162
172
md5.begin ();
163
- md5.add (String (username)+ " : " + _realm+ " : " + String (password)); // md5 of the user:realm:user
173
+ md5.add (String (username) + ' : ' + _realm + ' : ' + String (password)); // md5 of the user:realm:user
164
174
md5.calculate ();
165
175
String _H1 = md5.toString ();
166
176
#ifdef DEBUG_ESP_HTTP_SERVER
167
177
DEBUG_OUTPUT.println (" Hash of user:realm:pass=" + _H1);
168
178
#endif
169
179
md5.begin ();
170
180
if (_currentMethod == HTTP_GET){
171
- md5.add (" GET:" + _uri);
181
+ md5.add (String ( F ( " GET:" )) + _uri);
172
182
}else if (_currentMethod == HTTP_POST){
173
- md5.add (" POST:" + _uri);
183
+ md5.add (String ( F ( " POST:" )) + _uri);
174
184
}else if (_currentMethod == HTTP_PUT){
175
- md5.add (" PUT:" + _uri);
185
+ md5.add (String ( F ( " PUT:" )) + _uri);
176
186
}else if (_currentMethod == HTTP_DELETE){
177
- md5.add (" DELETE:" + _uri);
187
+ md5.add (String ( F ( " DELETE:" )) + _uri);
178
188
}else {
179
- md5.add (" GET:" + _uri);
189
+ md5.add (String ( F ( " GET:" )) + _uri);
180
190
}
181
191
md5.calculate ();
182
192
String _H2 = md5.toString ();
183
193
#ifdef DEBUG_ESP_HTTP_SERVER
184
194
DEBUG_OUTPUT.println (" Hash of GET:uri=" + _H2);
185
195
#endif
186
196
md5.begin ();
187
- if (authReq.indexOf (" qop=auth " ) != -1 ){
188
- md5.add (_H1+ " : " + _nonce+ " : " + _nc+ " : " + _cnonce+ " :auth:" + _H2);
197
+ if (authReq.indexOf (FPSTR (qop_auth)) != -1 ) {
198
+ md5.add (_H1 + FPSTR (colon) + _nonce + FPSTR (colon) + _nc + FPSTR (colon) + _cnonce + ' :auth:' + _H2);
189
199
}else {
190
- md5.add (_H1+ " : " + _nonce+ " : " + _H2);
200
+ md5.add (_H1 + FPSTR (colon) + _nonce + FPSTR (colon) + _H2);
191
201
}
192
202
md5.calculate ();
193
203
String _responsecheck = md5.toString ();
194
204
#ifdef DEBUG_ESP_HTTP_SERVER
195
205
DEBUG_OUTPUT.println (" The Proper response=" +_responsecheck);
196
206
#endif
197
- if (_response== _responsecheck){
198
- authReq = String () ;
207
+ if (_response == _responsecheck){
208
+ authReq = " " ;
199
209
return true ;
200
210
}
201
211
}
202
- authReq = String () ;
212
+ authReq = " " ;
203
213
}
204
214
return false ;
205
215
}
206
216
207
- String ESP8266WebServer::_getRandomHexString (){
217
+ String ESP8266WebServer::_getRandomHexString () {
208
218
char buffer[33 ]; // buffer to hold 32 Hex Digit + /0
209
219
int i;
210
- for (i= 0 ;i< 4 ; i++){
211
- sprintf (buffer+ (i*8 ), " %08x" , RANDOM_REG32);
220
+ for (i = 0 ; i < 4 ; i++) {
221
+ sprintf (buffer + (i*8 ), " %08x" , RANDOM_REG32);
212
222
}
213
223
return String (buffer);
214
224
}
215
225
216
- void ESP8266WebServer::requestAuthentication (HTTPAuthMethod mode, const char * realm, const String& authFailMsg){
217
- if (realm== NULL ){
218
- _srealm = " Login Required" ;
219
- }else {
226
+ void ESP8266WebServer::requestAuthentication (HTTPAuthMethod mode, const char * realm, const String& authFailMsg) {
227
+ if (realm == NULL ) {
228
+ _srealm = String ( F ( " Login Required" )) ;
229
+ } else {
220
230
_srealm = String (realm);
221
231
}
222
- if (mode== BASIC_AUTH){
223
- sendHeader (" WWW-Authenticate " , " Basic realm=\" " + _srealm + " \" " );
224
- }else {
232
+ if (mode == BASIC_AUTH) {
233
+ sendHeader (String ( FPSTR (WWW_Authenticate)), String ( F ( " Basic realm=\" " )) + _srealm + String ( F ( " \" " )) );
234
+ } else {
225
235
_snonce=_getRandomHexString ();
226
236
_sopaque=_getRandomHexString ();
227
- sendHeader (" WWW-Authenticate " , " Digest realm=\" " +_srealm + " \" , qop=\" auth\" , nonce=\" " + _snonce+ " \" , opaque=\" " + _sopaque+ " \" " );
237
+ sendHeader (String ( FPSTR (WWW_Authenticate)), String ( F ( " Digest realm=\" " )) +_srealm + String ( F ( " \" , qop=\" auth\" , nonce=\" " )) + _snonce + String ( F ( " \" , opaque=\" " )) + _sopaque + String ( F ( " \" " )) );
228
238
}
229
- send (401 ," text/html" ,authFailMsg);
239
+ using namespace mime ;
240
+ send (401 , mimeTable[html].mimeType , authFailMsg);
230
241
}
231
242
232
243
void ESP8266WebServer::on (const String &uri, ESP8266WebServer::THandlerFunction handler) {
@@ -327,6 +338,9 @@ void ESP8266WebServer::handleClient() {
327
338
328
339
void ESP8266WebServer::close () {
329
340
_server.close ();
341
+ _currentStatus = HC_NONE;
342
+ if (!_headerKeysCount)
343
+ collectHeaders (0 , 0 );
330
344
}
331
345
332
346
void ESP8266WebServer::stop () {
@@ -335,7 +349,7 @@ void ESP8266WebServer::stop() {
335
349
336
350
void ESP8266WebServer::sendHeader (const String& name, const String& value, bool first) {
337
351
String headerLine = name;
338
- headerLine += " : " ;
352
+ headerLine += F ( " : " ) ;
339
353
headerLine += value;
340
354
headerLine += " \r\n " ;
341
355
@@ -347,36 +361,37 @@ void ESP8266WebServer::sendHeader(const String& name, const String& value, bool
347
361
}
348
362
}
349
363
350
- void ESP8266WebServer::setContentLength (size_t contentLength) {
364
+ void ESP8266WebServer::setContentLength (const size_t contentLength) {
351
365
_contentLength = contentLength;
352
366
}
353
367
354
368
void ESP8266WebServer::_prepareHeader (String& response, int code, const char * content_type, size_t contentLength) {
355
- response = " HTTP/1." + String (_currentVersion)+ " " ;
369
+ response = String ( F ( " HTTP/1." )) + String (_currentVersion) + ' ' ;
356
370
response += String (code);
357
- response += " " ;
371
+ response += ' ' ;
358
372
response += _responseCodeToString (code);
359
373
response += " \r\n " ;
360
374
375
+ using namespace mime ;
361
376
if (!content_type)
362
- content_type = " text/ html" ;
377
+ content_type = mimeTable[ html]. mimeType ;
363
378
364
- sendHeader (" Content-Type" , content_type, true );
379
+ sendHeader (String ( F ( " Content-Type" )) , content_type, true );
365
380
if (_contentLength == CONTENT_LENGTH_NOT_SET) {
366
- sendHeader (" Content-Length " , String (contentLength));
381
+ sendHeader (String ( FPSTR (Content_Length)) , String (contentLength));
367
382
} else if (_contentLength != CONTENT_LENGTH_UNKNOWN) {
368
- sendHeader (" Content-Length " , String (_contentLength));
383
+ sendHeader (String ( FPSTR (Content_Length)) , String (_contentLength));
369
384
} else if (_contentLength == CONTENT_LENGTH_UNKNOWN && _currentVersion){ // HTTP/1.1 or above client
370
385
// let's do chunked
371
386
_chunked = true ;
372
- sendHeader (" Accept-Ranges" , " none" );
373
- sendHeader (" Transfer-Encoding" , " chunked" );
387
+ sendHeader (String ( F ( " Accept-Ranges" )), String ( F ( " none" )) );
388
+ sendHeader (String ( F ( " Transfer-Encoding" )), String ( F ( " chunked" )) );
374
389
}
375
- sendHeader (" Connection" , " close" );
390
+ sendHeader (String ( F ( " Connection" )), String ( F ( " close" )) );
376
391
377
392
response += _responseHeaders;
378
393
response += " \r\n " ;
379
- _responseHeaders = String () ;
394
+ _responseHeaders = " " ;
380
395
}
381
396
382
397
void ESP8266WebServer::send (int code, const char * content_type, const String& content) {
@@ -466,24 +481,37 @@ void ESP8266WebServer::sendContent_P(PGM_P content, size_t size) {
466
481
}
467
482
468
483
484
+ void ESP8266WebServer::_streamFileCore (const size_t fileSize, const String & fileName, const String & contentType)
485
+ {
486
+ using namespace mime ;
487
+ setContentLength (fileSize);
488
+ if (fileName.endsWith (mimeTable[gz].endsWith ) &&
489
+ contentType != mimeTable[gz].mimeType &&
490
+ contentType != mimeTable[none].mimeType ) {
491
+ sendHeader (F (" Content-Encoding" ), F (" gzip" ));
492
+ }
493
+ send (200 , contentType, " " );
494
+ }
495
+
496
+
469
497
String ESP8266WebServer::arg (String name) {
470
498
for (int i = 0 ; i < _currentArgCount; ++i) {
471
499
if ( _currentArgs[i].key == name )
472
500
return _currentArgs[i].value ;
473
501
}
474
- return String () ;
502
+ return " " ;
475
503
}
476
504
477
505
String ESP8266WebServer::arg (int i) {
478
506
if (i < _currentArgCount)
479
507
return _currentArgs[i].value ;
480
- return String () ;
508
+ return " " ;
481
509
}
482
510
483
511
String ESP8266WebServer::argName (int i) {
484
512
if (i < _currentArgCount)
485
513
return _currentArgs[i].key ;
486
- return String () ;
514
+ return " " ;
487
515
}
488
516
489
517
int ESP8266WebServer::args () {
@@ -504,15 +532,15 @@ String ESP8266WebServer::header(String name) {
504
532
if (_currentHeaders[i].key .equalsIgnoreCase (name))
505
533
return _currentHeaders[i].value ;
506
534
}
507
- return String () ;
535
+ return " " ;
508
536
}
509
537
510
538
void ESP8266WebServer::collectHeaders (const char * headerKeys[], const size_t headerKeysCount) {
511
539
_headerKeysCount = headerKeysCount + 1 ;
512
540
if (_currentHeaders)
513
541
delete[] _currentHeaders;
514
542
_currentHeaders = new RequestArgument[_headerKeysCount];
515
- _currentHeaders[0 ].key = AUTHORIZATION_HEADER;
543
+ _currentHeaders[0 ].key = FPSTR ( AUTHORIZATION_HEADER) ;
516
544
for (int i = 1 ; i < _headerKeysCount; i++){
517
545
_currentHeaders[i].key = headerKeys[i-1 ];
518
546
}
@@ -521,13 +549,13 @@ void ESP8266WebServer::collectHeaders(const char* headerKeys[], const size_t hea
521
549
String ESP8266WebServer::header (int i) {
522
550
if (i < _headerKeysCount)
523
551
return _currentHeaders[i].value ;
524
- return String () ;
552
+ return " " ;
525
553
}
526
554
527
555
String ESP8266WebServer::headerName (int i) {
528
556
if (i < _headerKeysCount)
529
557
return _currentHeaders[i].key ;
530
- return String () ;
558
+ return " " ;
531
559
}
532
560
533
561
int ESP8266WebServer::headers () {
@@ -574,13 +602,14 @@ void ESP8266WebServer::_handleRequest() {
574
602
handled = true ;
575
603
}
576
604
if (!handled) {
577
- send (404 , " text/plain" , String (" Not found: " ) + _currentUri);
605
+ using namespace mime ;
606
+ send (404 , mimeTable[html].mimeType , String (F (" Not found: " )) + _currentUri);
578
607
handled = true ;
579
608
}
580
609
if (handled) {
581
610
_finalizeResponse ();
582
611
}
583
- _currentUri = String () ;
612
+ _currentUri = " " ;
584
613
}
585
614
586
615
@@ -632,6 +661,6 @@ String ESP8266WebServer::_responseCodeToString(int code) {
632
661
case 503 : return F (" Service Unavailable" );
633
662
case 504 : return F (" Gateway Time-out" );
634
663
case 505 : return F (" HTTP Version not supported" );
635
- default : return " " ;
664
+ default : return F ( " " ) ;
636
665
}
637
666
}
0 commit comments