mirror of
https://github.com/esp8266/Arduino.git
synced 2025-07-27 18:02:17 +03:00
Merge remote-tracking branch 'remotes/esp8266/esp8266' into esp8266
Conflicts: hardware/esp8266com/esp8266/cores/esp8266/Updater.cpp hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/include/ClientContext.h
This commit is contained in:
@ -0,0 +1,135 @@
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <WiFiClient.h>
|
||||
#include <ESP8266WebServer.h>
|
||||
#include <DNSServer.h>
|
||||
#include <ESP8266mDNS.h>
|
||||
#include <EEPROM.h>
|
||||
|
||||
/*
|
||||
* This example serves a "hello world" on a WLAN and a SoftAP at the same time.
|
||||
* The SoftAP allow you to configure WLAN parameters at run time. They are not setup in the sketch but saved on EEPROM.
|
||||
*
|
||||
* Connect your computer or cell phone to wifi network ESP_ap with password 12345678. A popup may appear and it allow you to go to WLAN config. If it does not then navigate to http://192.168.4.1/wifi and config it there.
|
||||
* Then wait for the module to connect to your wifi and take note of the WLAN IP it got. Then you can disconnect from ESP_ap and return to your regular WLAN.
|
||||
*
|
||||
* Now the ESP8266 is in your network. You can reach it through http://192.168.x.x/ (the IP you took note of) or maybe at http://esp8266.local too.
|
||||
*
|
||||
* This is a captive portal because through the softAP it will redirect any http request to http://192.168.4.1/
|
||||
*/
|
||||
|
||||
/* Set these to your desired softAP credentials. They are not configurable at runtime */
|
||||
const char *softAP_ssid = "ESP_ap";
|
||||
const char *softAP_password = "12345678";
|
||||
|
||||
/* hostname for mDNS. Should work at least on windows. Try http://esp8266.local */
|
||||
const char *myHostname = "esp8266";
|
||||
|
||||
/* Don't set this wifi credentials. They are configurated at runtime and stored on EEPROM */
|
||||
char ssid[32] = "";
|
||||
char password[32] = "";
|
||||
|
||||
// DNS server
|
||||
const byte DNS_PORT = 53;
|
||||
DNSServer dnsServer;
|
||||
|
||||
// Web server
|
||||
ESP8266WebServer server(80);
|
||||
|
||||
/* Soft AP network parameters */
|
||||
IPAddress apIP(192, 168, 4, 1);
|
||||
IPAddress netMsk(255, 255, 255, 0);
|
||||
|
||||
|
||||
/** Should I connect to WLAN asap? */
|
||||
boolean connect;
|
||||
|
||||
/** Last time I tried to connect to WLAN */
|
||||
long lastConnectTry = 0;
|
||||
|
||||
/** Current WLAN status */
|
||||
int status = WL_IDLE_STATUS;
|
||||
|
||||
void setup() {
|
||||
delay(1000);
|
||||
Serial.begin(9600);
|
||||
Serial.println();
|
||||
Serial.print("Configuring access point...");
|
||||
/* You can remove the password parameter if you want the AP to be open. */
|
||||
WiFi.softAPConfig(apIP, apIP, netMsk);
|
||||
WiFi.softAP(softAP_ssid, softAP_password);
|
||||
delay(500); // Without delay I've seen the IP address blank
|
||||
Serial.print("AP IP address: ");
|
||||
Serial.println(WiFi.softAPIP());
|
||||
|
||||
/* Setup the DNS server redirecting all the domains to the apIP */
|
||||
dnsServer.setErrorReplyCode(DNSReplyCode::NoError);
|
||||
dnsServer.start(DNS_PORT, "*", apIP);
|
||||
|
||||
/* Setup web pages: root, wifi config pages, SO captive portal detectors and not found. */
|
||||
server.on("/", handleRoot);
|
||||
server.on("/wifi", handleWifi);
|
||||
server.on("/wifisave", handleWifiSave);
|
||||
server.on("/generate_204", handleRoot); //Android captive portal. Maybe not needed. Might be handled by notFound handler.
|
||||
server.on("/fwlink", handleRoot); //Microsoft captive portal. Maybe not needed. Might be handled by notFound handler.
|
||||
server.onNotFound ( handleNotFound );
|
||||
server.begin(); // Web server start
|
||||
Serial.println("HTTP server started");
|
||||
loadCredentials(); // Load WLAN credentials from network
|
||||
connect = strlen(ssid) > 0; // Request WLAN connect if there is a SSID
|
||||
}
|
||||
|
||||
void connectWifi() {
|
||||
Serial.println("Connecting as wifi client...");
|
||||
WiFi.disconnect();
|
||||
WiFi.begin ( ssid, password );
|
||||
int connRes = WiFi.waitForConnectResult();
|
||||
Serial.print ( "connRes: " );
|
||||
Serial.println ( connRes );
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (connect) {
|
||||
Serial.println ( "Connect requested" );
|
||||
connect = false;
|
||||
connectWifi();
|
||||
lastConnectTry = millis();
|
||||
}
|
||||
{
|
||||
int s = WiFi.status();
|
||||
if (s == 0 && millis() > (lastConnectTry + 60000) ) {
|
||||
/* If WLAN disconnected and idle try to connect */
|
||||
/* Don't set retry time too low as retry interfere the softAP operation */
|
||||
connect = true;
|
||||
}
|
||||
if (status != s) { // WLAN status change
|
||||
Serial.print ( "Status: " );
|
||||
Serial.println ( s );
|
||||
status = s;
|
||||
if (s == WL_CONNECTED) {
|
||||
/* Just connected to WLAN */
|
||||
Serial.println ( "" );
|
||||
Serial.print ( "Connected to " );
|
||||
Serial.println ( ssid );
|
||||
Serial.print ( "IP address: " );
|
||||
Serial.println ( WiFi.localIP() );
|
||||
|
||||
// Setup MDNS responder
|
||||
if (!MDNS.begin(myHostname)) {
|
||||
Serial.println("Error setting up MDNS responder!");
|
||||
} else {
|
||||
Serial.println("mDNS responder started");
|
||||
// Add service to MDNS-SD
|
||||
MDNS.addService("http", "tcp", 80);
|
||||
}
|
||||
} else if (s == WL_NO_SSID_AVAIL) {
|
||||
WiFi.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Do work:
|
||||
//DNS
|
||||
dnsServer.processNextRequest();
|
||||
//HTTP
|
||||
server.handleClient();
|
||||
}
|
||||
|
@ -0,0 +1,27 @@
|
||||
/** Load WLAN credentials from EEPROM */
|
||||
void loadCredentials() {
|
||||
EEPROM.begin(512);
|
||||
EEPROM.get(0, ssid);
|
||||
EEPROM.get(0+sizeof(ssid), password);
|
||||
char ok[2+1];
|
||||
EEPROM.get(0+sizeof(ssid)+sizeof(password), ok);
|
||||
EEPROM.end();
|
||||
if (String(ok) != String("OK")) {
|
||||
ssid[0] = 0;
|
||||
password[0] = 0;
|
||||
}
|
||||
Serial.println("Recovered credentials:");
|
||||
Serial.println(ssid);
|
||||
Serial.println(strlen(password)>0?"********":"<no password>");
|
||||
}
|
||||
|
||||
/** Store WLAN credentials to EEPROM */
|
||||
void saveCredentials() {
|
||||
EEPROM.begin(512);
|
||||
EEPROM.put(0, ssid);
|
||||
EEPROM.put(0+sizeof(ssid), password);
|
||||
char ok[2+1] = "OK";
|
||||
EEPROM.put(0+sizeof(ssid)+sizeof(password), ok);
|
||||
EEPROM.commit();
|
||||
EEPROM.end();
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
/** Handle root or redirect to captive portal */
|
||||
void handleRoot() {
|
||||
if (captivePortal()) { // If caprive portal redirect instead of displaying the page.
|
||||
return;
|
||||
}
|
||||
server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
server.sendHeader("Pragma", "no-cache");
|
||||
server.sendHeader("Expires", "-1");
|
||||
server.send(200, "text/html", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves.
|
||||
server.sendContent(
|
||||
"<html><head></head><body>"
|
||||
"<h1>HELLO WORLD!!</h1>"
|
||||
);
|
||||
if (server.client().localIP() == apIP) {
|
||||
server.sendContent(String("<p>You are connected through the soft AP: ") + softAP_ssid + "</p>");
|
||||
} else {
|
||||
server.sendContent(String("<p>You are connected through the wifi network: ") + ssid + "</p>");
|
||||
}
|
||||
server.sendContent(
|
||||
"<p>You may want to <a href='/wifi'>config the wifi connection</a>.</p>"
|
||||
"</body></html>"
|
||||
);
|
||||
server.client().stop(); // Stop is needed because we sent no content length
|
||||
}
|
||||
|
||||
/** Redirect to captive portal if we got a request for another domain. Return true in that case so the page handler do not try to handle the request again. */
|
||||
boolean captivePortal() {
|
||||
if (!isIp(server.hostHeader()) && server.hostHeader() != (String(myHostname)+".local")) {
|
||||
Serial.print("Request redirected to captive portal");
|
||||
server.sendHeader("Location", String("http://") + toStringIp(server.client().localIP()), true);
|
||||
server.send ( 302, "text/plain", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves.
|
||||
server.client().stop(); // Stop is needed because we sent no content length
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Wifi config page handler */
|
||||
void handleWifi() {
|
||||
server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
server.sendHeader("Pragma", "no-cache");
|
||||
server.sendHeader("Expires", "-1");
|
||||
server.send(200, "text/html", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves.
|
||||
server.sendContent(
|
||||
"<html><head></head><body>"
|
||||
"<h1>Wifi config</h1>"
|
||||
);
|
||||
if (server.client().localIP() == apIP) {
|
||||
server.sendContent(String("<p>You are connected through the soft AP: ") + softAP_ssid + "</p>");
|
||||
} else {
|
||||
server.sendContent(String("<p>You are connected through the wifi network: ") + ssid + "</p>");
|
||||
}
|
||||
server.sendContent(
|
||||
"\r\n<br />"
|
||||
"<table><tr><th align='left'>SoftAP config</th></tr>"
|
||||
);
|
||||
server.sendContent(String() + "<tr><td>SSID " + String(softAP_ssid) + "</td></tr>");
|
||||
server.sendContent(String() + "<tr><td>IP " + toStringIp(WiFi.softAPIP()) + "</td></tr>");
|
||||
server.sendContent(
|
||||
"</table>"
|
||||
"\r\n<br />"
|
||||
"<table><tr><th align='left'>WLAN config</th></tr>"
|
||||
);
|
||||
server.sendContent(String() + "<tr><td>SSID " + String(ssid) + "</td></tr>");
|
||||
server.sendContent(String() + "<tr><td>IP " + toStringIp(WiFi.localIP()) + "</td></tr>");
|
||||
server.sendContent(
|
||||
"</table>"
|
||||
"\r\n<br />"
|
||||
"<table><tr><th align='left'>WLAN list (refresh if any missing)</th></tr>"
|
||||
);
|
||||
Serial.println("scan start");
|
||||
int n = WiFi.scanNetworks();
|
||||
Serial.println("scan done");
|
||||
if (n > 0) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
server.sendContent(String() + "\r\n<tr><td>SSID " + String(WiFi.SSID(i)) + String((WiFi.encryptionType(i) == ENC_TYPE_NONE)?" ":" *") + " (" + WiFi.RSSI(i) + ")</td></tr>");
|
||||
}
|
||||
} else {
|
||||
server.sendContent(String() + "<tr><td>No WLAN found</td></tr>");
|
||||
}
|
||||
server.sendContent(
|
||||
"</table>"
|
||||
"\r\n<br /><form method='POST' action='wifisave'><h4>Connect to network:</h4>"
|
||||
"<input type='text' placeholder='network' name='n'/>"
|
||||
"<br /><input type='password' placeholder='password' name='p'/>"
|
||||
"<br /><input type='submit' value='Connect/Disconnect'/></form>"
|
||||
"<p>You may want to <a href='/'>return to the home page</a>.</p>"
|
||||
"</body></html>"
|
||||
);
|
||||
server.client().stop(); // Stop is needed because we sent no content length
|
||||
}
|
||||
|
||||
/** Handle the WLAN save form and redirect to WLAN config page again */
|
||||
void handleWifiSave() {
|
||||
Serial.println("wifi save");
|
||||
server.arg("n").toCharArray(ssid, sizeof(ssid) - 1);
|
||||
server.arg("p").toCharArray(password, sizeof(password) - 1);
|
||||
server.sendHeader("Location", "wifi", true);
|
||||
server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
server.sendHeader("Pragma", "no-cache");
|
||||
server.sendHeader("Expires", "-1");
|
||||
server.send ( 302, "text/plain", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves.
|
||||
server.client().stop(); // Stop is needed because we sent no content length
|
||||
saveCredentials();
|
||||
connect = strlen(ssid) > 0; // Request WLAN connect with new credentials if there is a SSID
|
||||
}
|
||||
|
||||
void handleNotFound() {
|
||||
if (captivePortal()) { // If caprive portal redirect instead of displaying the error page.
|
||||
return;
|
||||
}
|
||||
String message = "File Not Found\n\n";
|
||||
message += "URI: ";
|
||||
message += server.uri();
|
||||
message += "\nMethod: ";
|
||||
message += ( server.method() == HTTP_GET ) ? "GET" : "POST";
|
||||
message += "\nArguments: ";
|
||||
message += server.args();
|
||||
message += "\n";
|
||||
|
||||
for ( uint8_t i = 0; i < server.args(); i++ ) {
|
||||
message += " " + server.argName ( i ) + ": " + server.arg ( i ) + "\n";
|
||||
}
|
||||
server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
server.sendHeader("Pragma", "no-cache");
|
||||
server.sendHeader("Expires", "-1");
|
||||
server.send ( 404, "text/plain", message );
|
||||
}
|
||||
|
21
libraries/DNSServer/examples/CaptivePortalAdvanced/tools.ino
Normal file
21
libraries/DNSServer/examples/CaptivePortalAdvanced/tools.ino
Normal file
@ -0,0 +1,21 @@
|
||||
/** Is this an IP? */
|
||||
boolean isIp(String str) {
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
int c = str.charAt(i);
|
||||
if (c != '.' && (c < '0' || c > '9')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** IP to String? */
|
||||
String toStringIp(IPAddress ip) {
|
||||
String res = "";
|
||||
for (int i = 0; i < 3; i++) {
|
||||
res += String((ip >> (8 * i)) & 0xFF) + ".";
|
||||
}
|
||||
res += String(((ip >> 8 * 3)) & 0xFF);
|
||||
return res;
|
||||
}
|
||||
|
@ -2,6 +2,9 @@
|
||||
#include <lwip/def.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
#define DEBUG
|
||||
#define DEBUG_OUTPUT Serial
|
||||
|
||||
DNSServer::DNSServer()
|
||||
{
|
||||
_ttl = htonl(60);
|
||||
@ -110,16 +113,43 @@ void DNSServer::replyWithIP()
|
||||
{
|
||||
_dnsHeader->QR = DNS_QR_RESPONSE;
|
||||
_dnsHeader->ANCount = _dnsHeader->QDCount;
|
||||
_dnsHeader->QDCount = 0;
|
||||
_dnsHeader->QDCount = _dnsHeader->QDCount;
|
||||
//_dnsHeader->RA = 1;
|
||||
|
||||
_udp.beginPacket(_udp.remoteIP(), _udp.remotePort());
|
||||
_udp.write(_buffer, _currentPacketSize);
|
||||
|
||||
_udp.write((uint8_t)192); // answer name is a pointer
|
||||
_udp.write((uint8_t)12); // pointer to offset at 0x00c
|
||||
|
||||
_udp.write((uint8_t)0); // 0x0001 answer is type A query (host address)
|
||||
_udp.write((uint8_t)1);
|
||||
|
||||
_udp.write((uint8_t)0); //0x0001 answer is class IN (internet address)
|
||||
_udp.write((uint8_t)1);
|
||||
|
||||
_udp.write((unsigned char*)&_ttl, 4);
|
||||
|
||||
// Length of RData is 4 bytes (because, in this case, RData is IPv4)
|
||||
_udp.write((uint8_t)0);
|
||||
_udp.write((uint8_t)4);
|
||||
_udp.write(_resolvedIP, sizeof(_resolvedIP));
|
||||
_udp.endPacket();
|
||||
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
DEBUG_OUTPUT.print("DNS responds: ");
|
||||
DEBUG_OUTPUT.print(_resolvedIP[0]);
|
||||
DEBUG_OUTPUT.print(".");
|
||||
DEBUG_OUTPUT.print(_resolvedIP[1]);
|
||||
DEBUG_OUTPUT.print(".");
|
||||
DEBUG_OUTPUT.print(_resolvedIP[2]);
|
||||
DEBUG_OUTPUT.print(".");
|
||||
DEBUG_OUTPUT.print(_resolvedIP[3]);
|
||||
DEBUG_OUTPUT.print(" for ");
|
||||
DEBUG_OUTPUT.println(getDomainNameWithoutWwwPrefix());
|
||||
#endif
|
||||
}
|
||||
|
||||
void DNSServer::replyWithCustomCode()
|
||||
@ -131,4 +161,4 @@ void DNSServer::replyWithCustomCode()
|
||||
_udp.beginPacket(_udp.remoteIP(), _udp.remotePort());
|
||||
_udp.write(_buffer, sizeof(DNSHeader));
|
||||
_udp.endPacket();
|
||||
}
|
||||
}
|
@ -68,4 +68,4 @@ class DNSServer
|
||||
void replyWithIP();
|
||||
void replyWithCustomCode();
|
||||
};
|
||||
#endif
|
||||
#endif
|
@ -24,8 +24,8 @@
|
||||
#include <Arduino.h>
|
||||
#include "WiFiServer.h"
|
||||
#include "WiFiClient.h"
|
||||
#include "FS.h"
|
||||
#include "ESP8266WebServer.h"
|
||||
#include "FS.h"
|
||||
#include "detail/RequestHandler.h"
|
||||
// #define DEBUG
|
||||
#define DEBUG_OUTPUT Serial
|
||||
@ -181,7 +181,7 @@ void ESP8266WebServer::sendContent(const String& content) {
|
||||
const size_t unit_size = HTTP_DOWNLOAD_UNIT_SIZE;
|
||||
size_t size_to_send = content.length();
|
||||
const char* send_start = content.c_str();
|
||||
|
||||
|
||||
while (size_to_send) {
|
||||
size_t will_send = (size_to_send < unit_size) ? size_to_send : unit_size;
|
||||
size_t sent = _currentClient.write(send_start, will_send);
|
||||
@ -253,6 +253,10 @@ bool ESP8266WebServer::hasArg(const char* name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String ESP8266WebServer::hostHeader() {
|
||||
return _hostHeader;
|
||||
}
|
||||
|
||||
void ESP8266WebServer::onFileUpload(THandlerFunction fn) {
|
||||
_fileUploadHandler = fn;
|
||||
}
|
||||
|
@ -38,7 +38,10 @@ enum HTTPUploadStatus { UPLOAD_FILE_START, UPLOAD_FILE_WRITE, UPLOAD_FILE_END };
|
||||
#define CONTENT_LENGTH_NOT_SET ((size_t) -2)
|
||||
|
||||
class RequestHandler;
|
||||
|
||||
namespace fs {
|
||||
class FS;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
HTTPUploadStatus status;
|
||||
@ -62,7 +65,7 @@ public:
|
||||
typedef std::function<void(void)> THandlerFunction;
|
||||
void on(const char* uri, THandlerFunction handler);
|
||||
void on(const char* uri, HTTPMethod method, THandlerFunction fn);
|
||||
void serveStatic(const char* uri, FS& fs, const char* path);
|
||||
void serveStatic(const char* uri, fs::FS& fs, const char* path);
|
||||
void onNotFound(THandlerFunction fn); //called when handler is not assigned
|
||||
void onFileUpload(THandlerFunction fn); //handle file uploads
|
||||
|
||||
@ -77,6 +80,8 @@ public:
|
||||
int args(); // get arguments count
|
||||
bool hasArg(const char* name); // check if argument exists
|
||||
|
||||
String hostHeader(); // get request host header if available or empty String if not
|
||||
|
||||
// send response to the client
|
||||
// code - HTTP response code, can be 200 or 404
|
||||
// content_type - HTTP content type, like "text/plain" or "image/png"
|
||||
@ -108,7 +113,7 @@ protected:
|
||||
bool _parseRequest(WiFiClient& client);
|
||||
void _parseArguments(String data);
|
||||
static const char* _responseCodeToString(int code);
|
||||
void _parseForm(WiFiClient& client, String boundary, uint32_t len);
|
||||
bool _parseForm(WiFiClient& client, String boundary, uint32_t len);
|
||||
void _uploadWriteByte(uint8_t b);
|
||||
uint8_t _uploadReadByte(WiFiClient& client);
|
||||
void _prepareHeader(String& response, int code, const char* content_type, size_t contentLength);
|
||||
@ -131,6 +136,8 @@ protected:
|
||||
size_t _contentLength;
|
||||
String _responseHeaders;
|
||||
|
||||
String _hostHeader;
|
||||
|
||||
RequestHandler* _firstHandler;
|
||||
RequestHandler* _lastHandler;
|
||||
THandlerFunction _notFoundHandler;
|
||||
|
@ -1,8 +1,8 @@
|
||||
/*
|
||||
/*
|
||||
Parsing.cpp - HTTP request parsing.
|
||||
|
||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
@ -24,8 +24,8 @@
|
||||
#include "WiFiClient.h"
|
||||
#include "ESP8266WebServer.h"
|
||||
|
||||
// #define DEBUG
|
||||
#define DEBUG_OUTPUT Serial1
|
||||
#define DEBUG
|
||||
#define DEBUG_OUTPUT Serial
|
||||
|
||||
bool ESP8266WebServer::_parseRequest(WiFiClient& client) {
|
||||
// Read the first line of HTTP request
|
||||
@ -43,7 +43,7 @@ bool ESP8266WebServer::_parseRequest(WiFiClient& client) {
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
String methodStr = req.substring(0, addr_start);
|
||||
String url = req.substring(addr_start + 1, addr_end);
|
||||
String searchStr = "";
|
||||
@ -53,7 +53,7 @@ bool ESP8266WebServer::_parseRequest(WiFiClient& client) {
|
||||
url = url.substring(0, hasSearch);
|
||||
}
|
||||
_currentUri = url;
|
||||
|
||||
|
||||
HTTPMethod method = HTTP_GET;
|
||||
if (methodStr == "POST") {
|
||||
method = HTTP_POST;
|
||||
@ -65,7 +65,7 @@ bool ESP8266WebServer::_parseRequest(WiFiClient& client) {
|
||||
method = HTTP_PATCH;
|
||||
}
|
||||
_currentMethod = method;
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
DEBUG_OUTPUT.print("method: ");
|
||||
DEBUG_OUTPUT.print(methodStr);
|
||||
@ -94,6 +94,14 @@ bool ESP8266WebServer::_parseRequest(WiFiClient& client) {
|
||||
}
|
||||
headerName = req.substring(0, headerDiv);
|
||||
headerValue = req.substring(headerDiv + 2);
|
||||
|
||||
#ifdef DEBUG
|
||||
DEBUG_OUTPUT.print("headerName: ");
|
||||
DEBUG_OUTPUT.println(headerName);
|
||||
DEBUG_OUTPUT.print("headerValue: ");
|
||||
DEBUG_OUTPUT.println(headerValue);
|
||||
#endif
|
||||
|
||||
if (headerName == "Content-Type"){
|
||||
if (headerValue.startsWith("text/plain")){
|
||||
isForm = false;
|
||||
@ -103,9 +111,11 @@ bool ESP8266WebServer::_parseRequest(WiFiClient& client) {
|
||||
}
|
||||
} else if (headerName == "Content-Length"){
|
||||
contentLength = headerValue.toInt();
|
||||
} else if (headerName == "Host"){
|
||||
_hostHeader = headerValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!isForm){
|
||||
if (searchStr != "") searchStr += '&';
|
||||
//some clients send headers first and data after (like we do)
|
||||
@ -131,9 +141,36 @@ bool ESP8266WebServer::_parseRequest(WiFiClient& client) {
|
||||
}
|
||||
_parseArguments(searchStr);
|
||||
if (isForm){
|
||||
_parseForm(client, boundaryStr, contentLength);
|
||||
if (!_parseForm(client, boundaryStr, contentLength)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String headerName;
|
||||
String headerValue;
|
||||
//parse headers
|
||||
while(1){
|
||||
req = client.readStringUntil('\r');
|
||||
client.readStringUntil('\n');
|
||||
if (req == "") break;//no moar headers
|
||||
int headerDiv = req.indexOf(':');
|
||||
if (headerDiv == -1){
|
||||
break;
|
||||
}
|
||||
headerName = req.substring(0, headerDiv);
|
||||
headerValue = req.substring(headerDiv + 2);
|
||||
|
||||
#ifdef DEBUG
|
||||
DEBUG_OUTPUT.print("headerName: ");
|
||||
DEBUG_OUTPUT.println(headerName);
|
||||
DEBUG_OUTPUT.print("headerValue: ");
|
||||
DEBUG_OUTPUT.println(headerValue);
|
||||
#endif
|
||||
|
||||
if (headerName == "Host"){
|
||||
_hostHeader = headerValue;
|
||||
}
|
||||
}
|
||||
_parseArguments(searchStr);
|
||||
}
|
||||
client.flush();
|
||||
@ -242,8 +279,8 @@ uint8_t ESP8266WebServer::_uploadReadByte(WiFiClient& client){
|
||||
return (uint8_t)res;
|
||||
}
|
||||
|
||||
void ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t len){
|
||||
|
||||
bool ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t len){
|
||||
|
||||
#ifdef DEBUG
|
||||
DEBUG_OUTPUT.print("Parse Form: Boundary: ");
|
||||
DEBUG_OUTPUT.print(boundary);
|
||||
@ -251,7 +288,12 @@ void ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t
|
||||
DEBUG_OUTPUT.println(len);
|
||||
#endif
|
||||
String line;
|
||||
line = client.readStringUntil('\r');
|
||||
int retry = 0;
|
||||
do {
|
||||
line = client.readStringUntil('\r');
|
||||
++retry;
|
||||
} while (line.length() == 0 && retry < 3);
|
||||
|
||||
client.readStringUntil('\n');
|
||||
//start reading the form
|
||||
if (line == ("--"+boundary)){
|
||||
@ -263,7 +305,7 @@ void ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t
|
||||
String argType;
|
||||
String argFilename;
|
||||
bool argIsFile = false;
|
||||
|
||||
|
||||
line = client.readStringUntil('\r');
|
||||
client.readStringUntil('\n');
|
||||
if (line.startsWith("Content-Disposition")){
|
||||
@ -314,11 +356,11 @@ void ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t
|
||||
DEBUG_OUTPUT.println(argValue);
|
||||
DEBUG_OUTPUT.println();
|
||||
#endif
|
||||
|
||||
|
||||
RequestArgument& arg = postArgs[postArgsLen++];
|
||||
arg.key = argName;
|
||||
arg.value = argValue;
|
||||
|
||||
|
||||
if (line == ("--"+boundary+"--")){
|
||||
#ifdef DEBUG
|
||||
DEBUG_OUTPUT.println("Done Parsing POST");
|
||||
@ -346,7 +388,7 @@ readfile:
|
||||
_uploadWriteByte(argByte);
|
||||
argByte = _uploadReadByte(client);
|
||||
}
|
||||
|
||||
|
||||
argByte = _uploadReadByte(client);
|
||||
if (argByte == 0x0A){
|
||||
argByte = _uploadReadByte(client);
|
||||
@ -365,10 +407,10 @@ readfile:
|
||||
goto readfile;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t endBuf[boundary.length()];
|
||||
client.readBytes(endBuf, boundary.length());
|
||||
|
||||
|
||||
if (strstr((const char*)endBuf, boundary.c_str()) != NULL){
|
||||
if (_fileUploadHandler) _fileUploadHandler();
|
||||
_currentUpload.totalSize += _currentUpload.currentSize;
|
||||
@ -412,7 +454,7 @@ readfile:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int iarg;
|
||||
int totalArgs = ((32 - postArgsLen) < _currentArgCount)?(32 - postArgsLen):_currentArgCount;
|
||||
for (iarg = 0; iarg < totalArgs; iarg++){
|
||||
@ -429,7 +471,11 @@ readfile:
|
||||
}
|
||||
_currentArgCount = iarg;
|
||||
if (postArgs) delete[] postArgs;
|
||||
return true;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
DEBUG_OUTPUT.print("Error: line: ");
|
||||
DEBUG_OUTPUT.println(line);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -263,6 +263,22 @@ uint16_t WiFiClient::remotePort()
|
||||
return _client->getRemotePort();
|
||||
}
|
||||
|
||||
IPAddress WiFiClient::localIP()
|
||||
{
|
||||
if (!_client)
|
||||
return IPAddress(0U);
|
||||
|
||||
return IPAddress(_client->getLocalAddress());
|
||||
}
|
||||
|
||||
uint16_t WiFiClient::localPort()
|
||||
{
|
||||
if (!_client)
|
||||
return 0;
|
||||
|
||||
return _client->getLocalPort();
|
||||
}
|
||||
|
||||
int8_t WiFiClient::_s_connected(void* arg, void* tpcb, int8_t err)
|
||||
{
|
||||
return reinterpret_cast<WiFiClient*>(arg)->_connected(tpcb, err);
|
||||
|
@ -60,6 +60,8 @@ public:
|
||||
|
||||
IPAddress remoteIP();
|
||||
uint16_t remotePort();
|
||||
IPAddress localIP();
|
||||
uint16_t localPort();
|
||||
bool getNoDelay();
|
||||
void setNoDelay(bool nodelay);
|
||||
static void setLocalPortStart(uint16_t port) { _localPort = port; }
|
||||
|
@ -125,6 +125,12 @@ class ClientContext {
|
||||
return _pcb->remote_port;
|
||||
}
|
||||
|
||||
uint32_t getLocalAddress() {
|
||||
if(!_pcb) return 0;
|
||||
|
||||
return _pcb->local_ip.addr;
|
||||
}
|
||||
|
||||
uint16_t getLocalPort() {
|
||||
if(!_pcb) return 0;
|
||||
|
||||
|
Reference in New Issue
Block a user