HttpServer Library for "mbed-os" which added a snapshot handler.
Dependents: GR-PEACH-webcam GR-Boards_WebCamera GR-Boards_WebCamera GR-Boards_WebCamera
Fork of HttpServer_snapshot by
HTTPServer.h@18:673d663a1ed7, 2019-09-13 (annotated)
- Committer:
- dkato
- Date:
- Fri Sep 13 02:08:33 2019 +0000
- Revision:
- 18:673d663a1ed7
- Parent:
- 17:6b7076372285
Add macro HTTP_SERVER_THREAD_MAX (default 1)
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
yueee_yt | 4:1b6b021ee21d | 1 | //#define _DEBUG_ALL |
yueee_yt | 4:1b6b021ee21d | 2 | |
yueee_yt | 0:fdf9c2c5200f | 3 | #ifndef HTTP_SERVER_H |
yueee_yt | 0:fdf9c2c5200f | 4 | #define HTTP_SERVER_H |
yueee_yt | 0:fdf9c2c5200f | 5 | |
yueee_yt | 4:1b6b021ee21d | 6 | #ifdef _DEBUG_ALL |
dkato | 15:371fbad587ed | 7 | #include <stdio.h> |
dkato | 15:371fbad587ed | 8 | #include <stdarg.h> |
dkato | 15:371fbad587ed | 9 | static inline void http_server_debug_print(const char *format, ...) { |
dkato | 15:371fbad587ed | 10 | va_list args; |
dkato | 15:371fbad587ed | 11 | va_start(args, format); |
dkato | 15:371fbad587ed | 12 | vfprintf(stderr, format, args); |
dkato | 15:371fbad587ed | 13 | va_end(args); |
dkato | 15:371fbad587ed | 14 | } |
dkato | 15:371fbad587ed | 15 | #else |
dkato | 15:371fbad587ed | 16 | static inline void http_server_debug_print(const char *format, ...) {} |
yueee_yt | 4:1b6b021ee21d | 17 | #endif |
yueee_yt | 4:1b6b021ee21d | 18 | |
yueee_yt | 0:fdf9c2c5200f | 19 | #include <string> |
yueee_yt | 0:fdf9c2c5200f | 20 | using std::string; |
yueee_yt | 0:fdf9c2c5200f | 21 | |
yueee_yt | 0:fdf9c2c5200f | 22 | #include <map> |
yueee_yt | 0:fdf9c2c5200f | 23 | using std::map; |
yueee_yt | 0:fdf9c2c5200f | 24 | |
yueee_yt | 0:fdf9c2c5200f | 25 | #include "HTTPRequestHandler.h" |
yueee_yt | 0:fdf9c2c5200f | 26 | #include "rtos.h" |
yueee_yt | 0:fdf9c2c5200f | 27 | #include "mbed.h" |
yueee_yt | 0:fdf9c2c5200f | 28 | |
yueee_yt | 0:fdf9c2c5200f | 29 | struct handlersComp { //Used to order handlers in the right way |
yueee_yt | 0:fdf9c2c5200f | 30 | bool operator() (const string& handler1, const string& handler2) const { |
yueee_yt | 0:fdf9c2c5200f | 31 | //The first handler is longer than the second one |
yueee_yt | 0:fdf9c2c5200f | 32 | if (handler1.length() > handler2.length()) |
yueee_yt | 0:fdf9c2c5200f | 33 | return true; //Returns true if handler1 is to appear before handler2 |
yueee_yt | 0:fdf9c2c5200f | 34 | else if (handler1.length() < handler2.length()) |
yueee_yt | 0:fdf9c2c5200f | 35 | return false; |
yueee_yt | 0:fdf9c2c5200f | 36 | else //To avoid the == case, sort now by address |
yueee_yt | 0:fdf9c2c5200f | 37 | return ((&handler1)>(&handler2)); |
yueee_yt | 0:fdf9c2c5200f | 38 | } |
yueee_yt | 0:fdf9c2c5200f | 39 | }; |
yueee_yt | 0:fdf9c2c5200f | 40 | |
dkato | 11:0700755d64ae | 41 | map< string, HTTPRequestHandler*(*)(const char*, const char* , TCPSocket* ), handlersComp > m_lpHandlers; |
yueee_yt | 0:fdf9c2c5200f | 42 | template<typename T> |
yueee_yt | 0:fdf9c2c5200f | 43 | void HTTPServerAddHandler(const char* path) //Template decl in header |
yueee_yt | 0:fdf9c2c5200f | 44 | { |
yueee_yt | 0:fdf9c2c5200f | 45 | m_lpHandlers[path] = &T::inst; |
yueee_yt | 0:fdf9c2c5200f | 46 | } |
yueee_yt | 0:fdf9c2c5200f | 47 | |
yueee_yt | 0:fdf9c2c5200f | 48 | void ListenThread(void const *args); |
yueee_yt | 0:fdf9c2c5200f | 49 | enum HTTP_METH { |
yueee_yt | 0:fdf9c2c5200f | 50 | HTTP_GET, |
yueee_yt | 0:fdf9c2c5200f | 51 | HTTP_POST, |
yueee_yt | 0:fdf9c2c5200f | 52 | HTTP_HEAD |
yueee_yt | 0:fdf9c2c5200f | 53 | }; |
yueee_yt | 0:fdf9c2c5200f | 54 | |
dkato | 11:0700755d64ae | 55 | bool getRequest(TCPSocket* client, string* path, string* meth) |
yueee_yt | 0:fdf9c2c5200f | 56 | { |
yueee_yt | 0:fdf9c2c5200f | 57 | char req[128]; |
yueee_yt | 0:fdf9c2c5200f | 58 | char c_path[128]; |
yueee_yt | 0:fdf9c2c5200f | 59 | char c_meth[128]; |
yueee_yt | 0:fdf9c2c5200f | 60 | const int maxLen = 128; |
yueee_yt | 0:fdf9c2c5200f | 61 | char* p = req; |
yueee_yt | 0:fdf9c2c5200f | 62 | //Read Line |
yueee_yt | 0:fdf9c2c5200f | 63 | int ret; |
yueee_yt | 0:fdf9c2c5200f | 64 | int len = 0; |
yueee_yt | 0:fdf9c2c5200f | 65 | for(int i = 0; i < maxLen - 1; i++) { |
dkato | 11:0700755d64ae | 66 | ret = client->recv(p, 1); |
dkato | 17:6b7076372285 | 67 | if(ret <= 0) { |
dkato | 17:6b7076372285 | 68 | return false; |
yueee_yt | 0:fdf9c2c5200f | 69 | } |
yueee_yt | 0:fdf9c2c5200f | 70 | if( (len > 1) && *(p-1)=='\r' && *p=='\n' ) { |
yueee_yt | 0:fdf9c2c5200f | 71 | p--; |
yueee_yt | 0:fdf9c2c5200f | 72 | len-=2; |
yueee_yt | 0:fdf9c2c5200f | 73 | break; |
yueee_yt | 0:fdf9c2c5200f | 74 | } else if( *p=='\n' ) { |
yueee_yt | 0:fdf9c2c5200f | 75 | len--; |
yueee_yt | 0:fdf9c2c5200f | 76 | break; |
yueee_yt | 0:fdf9c2c5200f | 77 | } |
yueee_yt | 0:fdf9c2c5200f | 78 | p++; |
yueee_yt | 0:fdf9c2c5200f | 79 | len++; |
yueee_yt | 0:fdf9c2c5200f | 80 | } |
yueee_yt | 0:fdf9c2c5200f | 81 | *p = 0; |
dkato | 15:371fbad587ed | 82 | http_server_debug_print("Parsing request : %s\r\n", req); |
yueee_yt | 0:fdf9c2c5200f | 83 | ret = sscanf(req, "%s %s HTTP/%*d.%*d", c_meth, c_path); |
yueee_yt | 0:fdf9c2c5200f | 84 | if(ret !=2) return false; |
yueee_yt | 0:fdf9c2c5200f | 85 | *meth = string(c_meth); |
yueee_yt | 0:fdf9c2c5200f | 86 | *path = string(c_path); |
yueee_yt | 0:fdf9c2c5200f | 87 | return true; |
yueee_yt | 0:fdf9c2c5200f | 88 | } |
yueee_yt | 0:fdf9c2c5200f | 89 | |
dkato | 11:0700755d64ae | 90 | void dispatchRequest(TCPSocket* client) |
yueee_yt | 0:fdf9c2c5200f | 91 | { |
yueee_yt | 0:fdf9c2c5200f | 92 | string path; |
yueee_yt | 0:fdf9c2c5200f | 93 | string meth; |
yueee_yt | 0:fdf9c2c5200f | 94 | HTTP_METH methCode; |
dkato | 15:371fbad587ed | 95 | http_server_debug_print("Dispatching req\r\n"); |
yueee_yt | 0:fdf9c2c5200f | 96 | if( !getRequest(client,&path, &meth ) ) { |
dkato | 15:371fbad587ed | 97 | http_server_debug_print("dispatchRequest Invalid request\r\n"); |
yueee_yt | 0:fdf9c2c5200f | 98 | return; //Invalid request |
yueee_yt | 0:fdf9c2c5200f | 99 | } |
yueee_yt | 0:fdf9c2c5200f | 100 | if( !meth.compare("GET") ) { |
dkato | 15:371fbad587ed | 101 | http_server_debug_print("dispatchRequest HTTP_GET\r\n"); |
yueee_yt | 0:fdf9c2c5200f | 102 | methCode = HTTP_GET; |
yueee_yt | 0:fdf9c2c5200f | 103 | } else if( !meth.compare("POST") ) { |
dkato | 15:371fbad587ed | 104 | http_server_debug_print("dispatchRequest HTTP_POST\r\n"); |
yueee_yt | 0:fdf9c2c5200f | 105 | methCode = HTTP_POST; |
yueee_yt | 0:fdf9c2c5200f | 106 | } else if( !meth.compare("HEAD") ) { |
dkato | 15:371fbad587ed | 107 | http_server_debug_print("dispatchRequest HTTP_HEAD\r\n"); |
yueee_yt | 0:fdf9c2c5200f | 108 | methCode = HTTP_HEAD; |
yueee_yt | 0:fdf9c2c5200f | 109 | } else { |
dkato | 15:371fbad587ed | 110 | http_server_debug_print("dispatchRequest() Parse error\r\n"); |
yueee_yt | 0:fdf9c2c5200f | 111 | return; |
yueee_yt | 0:fdf9c2c5200f | 112 | } |
dkato | 15:371fbad587ed | 113 | http_server_debug_print("Looking for a handler\r\n"); |
dkato | 11:0700755d64ae | 114 | map< string, HTTPRequestHandler*(*)(const char*, const char*, TCPSocket*), handlersComp >::iterator it; |
yueee_yt | 0:fdf9c2c5200f | 115 | int root_len = 0; |
yueee_yt | 0:fdf9c2c5200f | 116 | for (it = m_lpHandlers.begin(); it != m_lpHandlers.end(); it++) { |
dkato | 15:371fbad587ed | 117 | http_server_debug_print("Checking %s...\r\n", (*it).first.c_str()); |
yueee_yt | 0:fdf9c2c5200f | 118 | root_len = (*it).first.length(); |
yueee_yt | 0:fdf9c2c5200f | 119 | if ( root_len && |
yueee_yt | 0:fdf9c2c5200f | 120 | !path.compare( 0, root_len, (*it).first ) && |
yueee_yt | 0:fdf9c2c5200f | 121 | (path[root_len] == '/' || path[root_len] == '\0')) { |
dkato | 15:371fbad587ed | 122 | http_server_debug_print("Found (%s)\r\n", (*it).first.c_str()); |
yueee_yt | 0:fdf9c2c5200f | 123 | // Found! |
yueee_yt | 0:fdf9c2c5200f | 124 | break; // for |
yueee_yt | 0:fdf9c2c5200f | 125 | } |
yueee_yt | 0:fdf9c2c5200f | 126 | } |
yueee_yt | 0:fdf9c2c5200f | 127 | if((it == m_lpHandlers.end()) && !(m_lpHandlers.empty())) { |
dkato | 15:371fbad587ed | 128 | http_server_debug_print("Using default handler\r\n"); |
yueee_yt | 0:fdf9c2c5200f | 129 | it = m_lpHandlers.end(); |
yueee_yt | 0:fdf9c2c5200f | 130 | it--; //Get the last element |
yueee_yt | 0:fdf9c2c5200f | 131 | if( ! (((*it).first.length() == 0) || !(*it).first.compare("/")) ) //This is not the default handler |
yueee_yt | 0:fdf9c2c5200f | 132 | it = m_lpHandlers.end(); |
yueee_yt | 0:fdf9c2c5200f | 133 | root_len = 0; |
yueee_yt | 0:fdf9c2c5200f | 134 | } |
yueee_yt | 0:fdf9c2c5200f | 135 | if(it == m_lpHandlers.end()) { |
dkato | 15:371fbad587ed | 136 | http_server_debug_print("No handler found\r\n"); |
yueee_yt | 0:fdf9c2c5200f | 137 | return; |
yueee_yt | 0:fdf9c2c5200f | 138 | } |
dkato | 15:371fbad587ed | 139 | http_server_debug_print("Handler found.\r\n"); |
yueee_yt | 0:fdf9c2c5200f | 140 | HTTPRequestHandler* pHdlr = (*it).second((*it).first.c_str(), path.c_str() + root_len, client); |
yueee_yt | 0:fdf9c2c5200f | 141 | //**** client = NULL; //We don't own it anymore |
yueee_yt | 0:fdf9c2c5200f | 142 | switch(methCode) { |
yueee_yt | 0:fdf9c2c5200f | 143 | case HTTP_GET: |
yueee_yt | 0:fdf9c2c5200f | 144 | pHdlr->doGet(); |
yueee_yt | 0:fdf9c2c5200f | 145 | break; |
yueee_yt | 0:fdf9c2c5200f | 146 | case HTTP_POST: |
yueee_yt | 0:fdf9c2c5200f | 147 | pHdlr->doPost(); |
yueee_yt | 0:fdf9c2c5200f | 148 | break; |
yueee_yt | 0:fdf9c2c5200f | 149 | case HTTP_HEAD: |
yueee_yt | 0:fdf9c2c5200f | 150 | pHdlr->doHead(); |
yueee_yt | 0:fdf9c2c5200f | 151 | break; |
yueee_yt | 0:fdf9c2c5200f | 152 | } |
yueee_yt | 0:fdf9c2c5200f | 153 | delete pHdlr; |
dkato | 15:371fbad587ed | 154 | http_server_debug_print("(dispatcherRequest)return\r\n"); |
yueee_yt | 4:1b6b021ee21d | 155 | return ; |
yueee_yt | 0:fdf9c2c5200f | 156 | } |
yueee_yt | 0:fdf9c2c5200f | 157 | |
dkato | 18:673d663a1ed7 | 158 | #ifndef HTTP_SERVER_THREAD_MAX |
dkato | 18:673d663a1ed7 | 159 | #define HTTP_SERVER_THREAD_MAX 1 |
dkato | 18:673d663a1ed7 | 160 | #endif |
dkato | 15:371fbad587ed | 161 | |
dkato | 18:673d663a1ed7 | 162 | #if (HTTP_SERVER_THREAD_MAX > 1) |
dkato | 18:673d663a1ed7 | 163 | static Thread *threads[HTTP_SERVER_THREAD_MAX]; |
dkato | 18:673d663a1ed7 | 164 | static bool soket_rady[HTTP_SERVER_THREAD_MAX]; |
dkato | 18:673d663a1ed7 | 165 | static TCPSocket * clients[HTTP_SERVER_THREAD_MAX]; |
dkato | 15:371fbad587ed | 166 | |
dkato | 16:16289b6ec82a | 167 | static void HTTPServerChild (void* param) |
yueee_yt | 0:fdf9c2c5200f | 168 | { |
dkato | 16:16289b6ec82a | 169 | bool* p_rady = &soket_rady[(int)param]; |
yueee_yt | 0:fdf9c2c5200f | 170 | |
dkato | 16:16289b6ec82a | 171 | while (1) { |
dkato | 17:6b7076372285 | 172 | ThisThread::flags_wait_all(1); |
dkato | 17:6b7076372285 | 173 | TCPSocket* client = clients[(int)param]; |
yueee_yt | 0:fdf9c2c5200f | 174 | dispatchRequest(client); |
yueee_yt | 0:fdf9c2c5200f | 175 | client->close(); |
dkato | 16:16289b6ec82a | 176 | *p_rady = true; |
yueee_yt | 0:fdf9c2c5200f | 177 | } |
yueee_yt | 0:fdf9c2c5200f | 178 | } |
yueee_yt | 0:fdf9c2c5200f | 179 | |
dkato | 15:371fbad587ed | 180 | void HTTPServerStart(NetworkInterface *net, int port = 80, osPriority priority = osPriorityNormal) |
yueee_yt | 0:fdf9c2c5200f | 181 | { |
dkato | 16:16289b6ec82a | 182 | int i; |
dkato | 17:6b7076372285 | 183 | TCPSocket server; |
yueee_yt | 0:fdf9c2c5200f | 184 | |
dkato | 18:673d663a1ed7 | 185 | for (i = 0; i < HTTP_SERVER_THREAD_MAX; i++) { |
dkato | 16:16289b6ec82a | 186 | soket_rady[i] = true; |
dkato | 16:16289b6ec82a | 187 | threads[i] = new Thread(priority, 1024 * 3); |
dkato | 16:16289b6ec82a | 188 | threads[i]->start(callback(HTTPServerChild, (void *)i)); |
yueee_yt | 0:fdf9c2c5200f | 189 | } |
yueee_yt | 0:fdf9c2c5200f | 190 | |
dkato | 17:6b7076372285 | 191 | server.open(net); |
yueee_yt | 0:fdf9c2c5200f | 192 | server.bind(port); |
yueee_yt | 0:fdf9c2c5200f | 193 | server.listen(); |
dkato | 15:371fbad587ed | 194 | http_server_debug_print("Wait for new connection...\r\n"); |
dkato | 13:d3571c244759 | 195 | |
dkato | 16:16289b6ec82a | 196 | while (1) { |
dkato | 16:16289b6ec82a | 197 | while (1) { |
dkato | 18:673d663a1ed7 | 198 | for (i = 0; i < HTTP_SERVER_THREAD_MAX; i++) { |
dkato | 16:16289b6ec82a | 199 | if (soket_rady[i] != false) { |
dkato | 16:16289b6ec82a | 200 | break; |
yueee_yt | 0:fdf9c2c5200f | 201 | } |
yueee_yt | 0:fdf9c2c5200f | 202 | } |
dkato | 18:673d663a1ed7 | 203 | if (i < HTTP_SERVER_THREAD_MAX) { |
dkato | 16:16289b6ec82a | 204 | break; |
yueee_yt | 0:fdf9c2c5200f | 205 | } |
dkato | 16:16289b6ec82a | 206 | ThisThread::sleep_for(5); |
yueee_yt | 0:fdf9c2c5200f | 207 | } |
yueee_yt | 0:fdf9c2c5200f | 208 | |
dkato | 17:6b7076372285 | 209 | clients[i] = server.accept(); |
dkato | 17:6b7076372285 | 210 | if (clients[i] != NULL) { |
dkato | 16:16289b6ec82a | 211 | // fork child process |
dkato | 16:16289b6ec82a | 212 | soket_rady[i] = false; |
dkato | 17:6b7076372285 | 213 | threads[i]->flags_set(1); |
yueee_yt | 0:fdf9c2c5200f | 214 | } |
yueee_yt | 0:fdf9c2c5200f | 215 | } |
yueee_yt | 0:fdf9c2c5200f | 216 | } |
dkato | 15:371fbad587ed | 217 | |
dkato | 18:673d663a1ed7 | 218 | #else // HTTP_SERVER_THREAD_MAX == 1 |
dkato | 15:371fbad587ed | 219 | |
dkato | 15:371fbad587ed | 220 | void HTTPServerStart(NetworkInterface *net, int port = 80, osPriority priority = osPriorityNormal) |
dkato | 15:371fbad587ed | 221 | { |
dkato | 17:6b7076372285 | 222 | TCPSocket server; |
dkato | 17:6b7076372285 | 223 | TCPSocket * p_client; |
dkato | 15:371fbad587ed | 224 | |
dkato | 15:371fbad587ed | 225 | (void)priority; |
dkato | 15:371fbad587ed | 226 | |
dkato | 17:6b7076372285 | 227 | server.open(net); |
dkato | 15:371fbad587ed | 228 | server.bind(port); |
dkato | 15:371fbad587ed | 229 | server.listen(); |
dkato | 15:371fbad587ed | 230 | http_server_debug_print("Wait for new connection...\r\n"); |
dkato | 15:371fbad587ed | 231 | |
dkato | 15:371fbad587ed | 232 | while (1) { |
dkato | 17:6b7076372285 | 233 | p_client = server.accept(); |
dkato | 17:6b7076372285 | 234 | if (p_client != NULL) { |
dkato | 17:6b7076372285 | 235 | dispatchRequest(p_client); |
dkato | 17:6b7076372285 | 236 | p_client->close(); |
dkato | 15:371fbad587ed | 237 | } |
dkato | 15:371fbad587ed | 238 | } |
dkato | 15:371fbad587ed | 239 | } |
dkato | 15:371fbad587ed | 240 | |
dkato | 15:371fbad587ed | 241 | #endif |
dkato | 15:371fbad587ed | 242 | |
yueee_yt | 0:fdf9c2c5200f | 243 | #include "Handler/RPCHandler.h" |
yueee_yt | 0:fdf9c2c5200f | 244 | #include "Handler/FSHandler.h" |
yueee_yt | 0:fdf9c2c5200f | 245 | #include "Handler/SimpleHandler.h" |
dkato | 6:d9e6379eefac | 246 | #include "SnapshotHandler.h" |
yueee_yt | 0:fdf9c2c5200f | 247 | |
yueee_yt | 0:fdf9c2c5200f | 248 | #endif |