Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Uri with support for regexUri and globUri #6696

Merged
merged 28 commits into from
Feb 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
b80ea90
Add path args
bmooij-beeliners Oct 6, 2018
37f3d59
Add example
bmooij-beeliners Oct 6, 2018
41695e6
Update code format
bmooij-beeliners Oct 6, 2018
5dfa3f1
Add missing include
bmooij-beeliners Oct 6, 2018
ddb0f6f
Fix codestyle and unsigned int
bmooij-beeliners Oct 6, 2018
4e49e29
fix unsigned int
bmooij-beeliners Oct 6, 2018
1584859
Remove tabs
bmooij-beeliners Oct 8, 2018
da189ba
use vector<>.resize
bmooij-beeliners Oct 8, 2018
cabf620
rename j to requestUriIndex
bmooij-beeliners Oct 8, 2018
7cd3468
using assert checking the path argument index
bmooij-beeliners Oct 9, 2018
637b9cb
Add missing include "assert.h"
bmooij-beeliners Oct 9, 2018
63163d7
The order no longer matters.
bmooij-beeliners Oct 9, 2018
a626c5f
make pathArg return a const
bmooij-beeliners Oct 9, 2018
977120c
Update PathArgServer.ino
d-a-v Oct 10, 2018
de7b504
const String&
d-a-v Nov 30, 2018
879e076
Add regex support
bmooij-beeliners Dec 24, 2018
afe7854
Fix to match templating
bmooij-beeliners Nov 1, 2019
8f5eda3
Add Uri with support for staticUri, regexUri and globUri
bmooij-beeliners Nov 1, 2019
2ee04d0
Update example
bmooij-beeliners Nov 1, 2019
3edf15a
Add deconstructor to remove _uri pointer
bmooij-beeliners Nov 1, 2019
820597c
Add newline to end of files
bmooij-beeliners Nov 1, 2019
8d95fb6
Suppress gcc warnings (unused params)
bmooij-beeliners Nov 7, 2019
a856527
Merge branch 'master' into feature/multi_uri
Bmooij Nov 28, 2019
87e823c
Merge branch 'master' into feature/multi_uri
d-a-v Nov 28, 2019
baa4c49
Replace regex with regex.h
bmooij-beeliners Dec 27, 2019
f470387
Merge branch 'master' into feature/multi_uri
earlephilhower Feb 22, 2020
bb77646
Use the standard STASSID/PSK settings for example
earlephilhower Feb 22, 2020
be78c3b
Use 115.2Kbaud for example, match others
earlephilhower Feb 22, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>

#include <uri/UriBraces.h>
#include <uri/UriRegex.h>

#ifndef STASSID
#define STASSID "your-ssid"
#define STAPSK "your-password"
#endif

const char *ssid = STASSID;
const char *password = STAPSK;

ESP8266WebServer server(80);

void setup(void) {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println("");

// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());

if (MDNS.begin("esp8266")) {
Serial.println("MDNS responder started");
}

server.on("/", []() {
server.send(200, "text/plain", "hello from esp8266!");
});

server.on(UriBraces("/users/{}"), []() {
String user = server.pathArg(0);
server.send(200, "text/plain", "User: '" + user + "'");
});

server.on(UriRegex("^\\/users\\/([0-9]+)\\/devices\\/([0-9]+)$"), []() {
String user = server.pathArg(0);
String device = server.pathArg(1);
server.send(200, "text/plain", "User: '" + user + "' and Device: '" + device + "'");
});

server.begin();
Serial.println("HTTP server started");
}

void loop(void) {
server.handleClient();
}
12 changes: 9 additions & 3 deletions libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -263,17 +263,17 @@ void ESP8266WebServerTemplate<ServerType>::requestAuthentication(HTTPAuthMethod
}

template <typename ServerType>
void ESP8266WebServerTemplate<ServerType>::on(const String &uri, ESP8266WebServerTemplate<ServerType>::THandlerFunction handler) {
void ESP8266WebServerTemplate<ServerType>::on(const Uri &uri, ESP8266WebServerTemplate<ServerType>::THandlerFunction handler) {
on(uri, HTTP_ANY, handler);
}

template <typename ServerType>
void ESP8266WebServerTemplate<ServerType>::on(const String &uri, HTTPMethod method, ESP8266WebServerTemplate<ServerType>::THandlerFunction fn) {
void ESP8266WebServerTemplate<ServerType>::on(const Uri &uri, HTTPMethod method, ESP8266WebServerTemplate<ServerType>::THandlerFunction fn) {
on(uri, method, fn, _fileUploadHandler);
}

template <typename ServerType>
void ESP8266WebServerTemplate<ServerType>::on(const String &uri, HTTPMethod method, ESP8266WebServerTemplate<ServerType>::THandlerFunction fn, ESP8266WebServerTemplate<ServerType>::THandlerFunction ufn) {
void ESP8266WebServerTemplate<ServerType>::on(const Uri &uri, HTTPMethod method, ESP8266WebServerTemplate<ServerType>::THandlerFunction fn, ESP8266WebServerTemplate<ServerType>::THandlerFunction ufn) {
_addRequestHandler(new FunctionRequestHandler<ServerType>(fn, ufn, uri, method));
}

Expand Down Expand Up @@ -544,6 +544,12 @@ void ESP8266WebServerTemplate<ServerType>::_streamFileCore(const size_t fileSize
send(200, contentType, emptyString);
}

template <typename ServerType>
const String& ESP8266WebServerTemplate<ServerType>::pathArg(unsigned int i) const {
if (_currentHandler != nullptr)
return _currentHandler->pathArg(i);
return emptyString;
}

template <typename ServerType>
const String& ESP8266WebServerTemplate<ServerType>::arg(const String& name) const {
Expand Down
8 changes: 5 additions & 3 deletions libraries/ESP8266WebServer/src/ESP8266WebServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <ESP8266WiFi.h>
#include <FS.h>
#include "detail/mimetable.h"
#include "Uri.h"

enum HTTPMethod { HTTP_ANY, HTTP_GET, HTTP_HEAD, HTTP_POST, HTTP_PUT, HTTP_PATCH, HTTP_DELETE, HTTP_OPTIONS };
enum HTTPUploadStatus { UPLOAD_FILE_START, UPLOAD_FILE_WRITE, UPLOAD_FILE_END,
Expand Down Expand Up @@ -91,9 +92,9 @@ class ESP8266WebServerTemplate
void requestAuthentication(HTTPAuthMethod mode = BASIC_AUTH, const char* realm = NULL, const String& authFailMsg = String("") );

typedef std::function<void(void)> THandlerFunction;
void on(const String &uri, THandlerFunction handler);
void on(const String &uri, HTTPMethod method, THandlerFunction fn);
void on(const String &uri, HTTPMethod method, THandlerFunction fn, THandlerFunction ufn);
void on(const Uri &uri, THandlerFunction handler);
void on(const Uri &uri, HTTPMethod method, THandlerFunction fn);
void on(const Uri &uri, HTTPMethod method, THandlerFunction fn, THandlerFunction ufn);
void addHandler(RequestHandlerType* handler);
void serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header = NULL );
void onNotFound(THandlerFunction fn); //called when handler is not assigned
Expand All @@ -107,6 +108,7 @@ class ESP8266WebServerTemplate
// Allows setting server options (i.e. SSL keys) by the instantiator
ServerType &getServer() { return _server; }

const String& pathArg(unsigned int i) const; // get request path argument by number
const String& arg(const String& name) const; // get request argument value by name
const String& arg(int i) const; // get request argument value by number
const String& argName(int i) const; // get request argument name by number
Expand Down
26 changes: 26 additions & 0 deletions libraries/ESP8266WebServer/src/Uri.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#ifndef URI_H
#define URI_H

#include <Arduino.h>
#include <vector>

class Uri {

protected:
const String _uri;

public:
Uri(const char *uri) : _uri(uri) {}
Uri(const String &uri) : _uri(uri) {}
virtual ~Uri() {}

virtual Uri* clone() const {
return new Uri(_uri);
};

virtual bool canHandle(const String &requestUri, __attribute__((unused)) std::vector<String> &pathArgs) {
return _uri == requestUri;
}
};

#endif
11 changes: 11 additions & 0 deletions libraries/ESP8266WebServer/src/detail/RequestHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#define REQUESTHANDLER_H

#include <ESP8266WebServer.h>
#include <vector>
#include <assert.h>

template<typename ServerType>
class RequestHandler {
Expand All @@ -18,6 +20,15 @@ class RequestHandler {

private:
RequestHandler<ServerType>* _next = nullptr;

protected:
std::vector<String> pathArgs;

public:
const String& pathArg(unsigned int i) {
assert(i < pathArgs.size());
return pathArgs[i];
}
};

#endif //REQUESTHANDLER_H
16 changes: 9 additions & 7 deletions libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,31 @@
#include "RequestHandler.h"
#include "mimetable.h"
#include "WString.h"
#include "Uri.h"

using namespace mime;

template<typename ServerType>
class FunctionRequestHandler : public RequestHandler<ServerType> {
using WebServerType = ESP8266WebServerTemplate<ServerType>;
public:
FunctionRequestHandler(typename WebServerType::THandlerFunction fn, typename WebServerType::THandlerFunction ufn, const String &uri, HTTPMethod method)
FunctionRequestHandler(typename WebServerType::THandlerFunction fn, typename WebServerType::THandlerFunction ufn, const Uri &uri, HTTPMethod method)
: _fn(fn)
, _ufn(ufn)
, _uri(uri)
, _uri(uri.clone())
, _method(method)
{
}

~FunctionRequestHandler() {
delete _uri;
}

bool canHandle(HTTPMethod requestMethod, String requestUri) override {
if (_method != HTTP_ANY && _method != requestMethod)
return false;

if (requestUri != _uri)
return false;

return true;
return _uri->canHandle(requestUri, RequestHandler<ServerType>::pathArgs);
}

bool canUpload(String requestUri) override {
Expand Down Expand Up @@ -56,7 +58,7 @@ class FunctionRequestHandler : public RequestHandler<ServerType> {
protected:
typename WebServerType::THandlerFunction _fn;
typename WebServerType::THandlerFunction _ufn;
String _uri;
Uri *_uri;
HTTPMethod _method;
};

Expand Down
54 changes: 54 additions & 0 deletions libraries/ESP8266WebServer/src/uri/UriBraces.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#ifndef URI_BRACES_H
#define URI_BRACES_H

#include "Uri.h"

class UriBraces : public Uri {

public:
explicit UriBraces(const char *uri) : Uri(uri) {};
explicit UriBraces(const String &uri) : Uri(uri) {};

Uri* clone() const override final {
return new UriBraces(_uri);
};

bool canHandle(const String &requestUri, std::vector<String> &pathArgs) override final {
if (Uri::canHandle(requestUri, pathArgs))
return true;

pathArgs.clear();

size_t uriLength = _uri.length();
unsigned int requestUriIndex = 0;
for (unsigned int i = 0; i < uriLength; i++, requestUriIndex++) {
char uriChar = _uri[i];
char requestUriChar = requestUri[requestUriIndex];

if (uriChar == requestUriChar)
continue;
if (uriChar != '{')
return false;

i += 2; // index of char after '}'
if (i >= uriLength) {
// there is no char after '}'
pathArgs.push_back(requestUri.substring(requestUriIndex));
return pathArgs.back().indexOf("/") == -1; // path argument may not contain a '/'
}
else
{
char charEnd = _uri[i];
int uriIndex = requestUri.indexOf(charEnd, requestUriIndex);
if (uriIndex < 0)
return false;
pathArgs.push_back(requestUri.substring(requestUriIndex, uriIndex));
requestUriIndex = (unsigned int) uriIndex;
}
}

return requestUriIndex >= requestUri.length();
}
};

#endif
22 changes: 22 additions & 0 deletions libraries/ESP8266WebServer/src/uri/UriGlob.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#ifndef URI_GLOB_H
#define URI_GLOB_H

#include "Uri.h"
#include <fnmatch.h>

class UriGlob : public Uri {

public:
explicit UriGlob(const char *uri) : Uri(uri) {};
explicit UriGlob(const String &uri) : Uri(uri) {};

Uri* clone() const override final {
return new UriGlob(_uri);
};

bool canHandle(const String &requestUri, __attribute__((unused)) std::vector<String> &pathArgs) override final {
return fnmatch(_uri.c_str(), requestUri.c_str(), 0) == 0;
}
};

#endif
54 changes: 54 additions & 0 deletions libraries/ESP8266WebServer/src/uri/UriRegex.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#ifndef URI_REGEX_H
#define URI_REGEX_H

#include "Uri.h"
#include <regex.h>
#include <assert.h>

#ifndef REGEX_MAX_GROUPS
#define REGEX_MAX_GROUPS 10
#endif

class UriRegex : public Uri {

private:
regex_t _regexCompiled;

public:
explicit UriRegex(const char *uri) : Uri(uri) {
assert(regcomp(&_regexCompiled, uri, REG_EXTENDED) == 0);
};
explicit UriRegex(const String &uri) : UriRegex(uri.c_str()) {};

~UriRegex() {
regfree(&_regexCompiled);
}

Uri* clone() const override final {
return new UriRegex(_uri);
};

bool canHandle(const String &requestUri, std::vector<String> &pathArgs) override final {
if (Uri::canHandle(requestUri, pathArgs))
return true;

regmatch_t groupArray[REGEX_MAX_GROUPS];
if (regexec(&_regexCompiled, requestUri.c_str(), REGEX_MAX_GROUPS, groupArray, 0) == 0) {
// matches
pathArgs.clear();

unsigned int g = 1;
for (; g < REGEX_MAX_GROUPS; g++) {
if (groupArray[g].rm_so == (long int)-1)
break; // No more groups

pathArgs.push_back(requestUri.substring(groupArray[g].rm_so, groupArray[g].rm_eo));
}

return true;
}
return false;
}
};

#endif