Example of HTTPServer with additional features: * SNTPClient, DST rules * Link status indication * Local or SDCard-based WebServer * RPC-able class * Static and Dynamic HTML page
Revision 2:360fda42fefd, committed 2010-01-12
- Comitter:
- iva2k
- Date:
- Tue Jan 12 07:41:55 2010 +0000
- Parent:
- 1:ec4170739967
- Commit message:
Changed in this revision
--- a/lwip/Core/lwipopts.h Fri Jan 08 00:28:14 2010 +0000 +++ b/lwip/Core/lwipopts.h Tue Jan 12 07:41:55 2010 +0000 @@ -86,8 +86,8 @@ #endif #include <time.h> -extern unsigned int gSntpRecvTimeout_ms; -extern unsigned int gSntpUpdateDelay_ms; // Never set this below 15000 +extern unsigned int gSntpRecvTimeout_s; +extern unsigned int gSntpUpdateDelay_s; // Never set this below 15 void SntpClientSet(time_t sec); // Receives NTP timestamp #ifdef __cplusplus @@ -96,8 +96,7 @@ // Do not change these: #define SNTP_SOCKET 0 -#define SNTP_DEBUG LWIP_DBG_ON -#define PBUF_DEBUG LWIP_DBG_ON +#define SNTP_DEBUG LWIP_DBG_OFF #define SNTP_PORT 123 #define SNTP_SERVER_DNS 1 // Override. Use URLs. Do not use IP addresses! #define SNTP_SUPPORT_MULTIPLE_SERVERS 1 // Override. Allow multiple servers. @@ -106,8 +105,8 @@ * to send in request and compare in response. */ #define SNTP_GET_SYSTEM_TIME(sec, us) do { (sec) = 0; (us) = 0; } while(0) -#define SNTP_RECV_TIMEOUT gSntpRecvTimeout_ms -#define SNTP_UPDATE_DELAY gSntpUpdateDelay_ms +#define SNTP_RECV_TIMEOUT gSntpRecvTimeout_s +#define SNTP_UPDATE_DELAY gSntpUpdateDelay_s #define SNTP_SUPPRESS_DELAY_CHECK 1 // needed to substitute define with global // You can change these: @@ -118,7 +117,7 @@ "time-b.nist.gov", \ // comma-separated list of server URLs #define SNTP_CHECK_RESPONSE 2 // For now use more checks. Do not set above 2. -#define SNTP_STARTUP_DELAY 0 // ms, Should be randomized +#define SNTP_STARTUP_DELAY 0 // seconds, Should be randomized // END [iva2k] Defines for LWIP/sntp, using SNTPClient wrapper //------------------------------------------------------------------------------
--- a/lwip/HTTPServer/HTTPRPC.h Fri Jan 08 00:28:14 2010 +0000 +++ b/lwip/HTTPServer/HTTPRPC.h Tue Jan 12 07:41:55 2010 +0000 @@ -1,3 +1,8 @@ +// HTTPRPC.h +// Modified by iva2k +// Improved URL string handling +// + #ifndef HTTPRPC_H #define HTTPRPC_H @@ -6,6 +11,10 @@ #ifdef MBED_RPC #include "rpc.h" +#ifndef HTTPRPC_USE_URI_FIELDS +#define HTTPRPC_USE_URI_FIELDS 1 +#endif + /** * A datastorage helper for the HTTPRPC class */ @@ -25,7 +34,7 @@ */ HTTPRPC(const char *path = "/rpc") : HTTPHandler(path) {} HTTPRPC(HTTPServer *server, const char *path = "/rpc") : HTTPHandler(path) { server->addHandler(this); } - + private: /** * If you need some Headerfeelds you have tor register the feelds here. @@ -44,7 +53,7 @@ HTTPRPCData *data = new HTTPRPCData(); con->data = data; char *query = con->getURL()+strlen(_prefix); - clean(query); + query = clean(query); rpc(query, data->result); const char *nfields = "Cache-Control: no-cache, no-store, must-revalidate\r\nPragma: no-cache\r\nExpires: Thu, 01 Dec 1994 16:00:00 GM"; @@ -83,7 +92,7 @@ * If we have not enought space wait for next time. */ virtual HTTPHandle send(HTTPConnection *con, int maximum) const { - HTTPRPCData *data = static_cast<HTTPRPCData *>(con->data); + HTTPRPCData *data = static_cast<HTTPRPCData *>(con->data); if(maximum>64) { con->write(data->result, con->getLength()); return HTTP_SuccessEnded; @@ -93,21 +102,144 @@ } } + inline bool is_hex(const char a) const { + return (a>='0' && a<='9') || (a>='A' && a<='F') || (a>='a' && a<='f'); + } + inline char hex_nib(const char a) const { + return 0xf & ( + (a>='0' && a<='9') ? (a-'0' ) : + (a>='A' && a<='F') ? (a-'A'+10) : + (a>='a' && a<='f') ? (a-'a'+10) : 0 + ); + } + inline char hex_byte(const char *str) const { + return (hex_nib(*str) << 4) | hex_nib(*(str+1)); + } /** - * To reduce memory usage we sodify the URL directly + * To reduce memory usage we sodify the URL directly * and replace '%20',',','+','=' with spaces. */ - inline void clean(char *str) const { - while(*str++) { - if(*str=='%'&&*(str+1)=='2'&&*(str+2)=='0') { - *str = ' '; - *(str+1) = ' '; - *(str+2) = ' '; +// mutable char _buf[1024]; + inline char *clean(char *str) const { + char *in = str; +// char *out = _buf; + char *out = str; // this will do conversions in-place. + bool inquotes=false; + bool backslash=false; + bool hasquery=false; + bool cantquery=false; + // cantquery=true will indicate that the URI already has symbols + // incompatible with query, so it disables checking for query. +#if HTTPRPC_USE_URI_FIELDS + bool infield=false; +// bool rpcquery=false; + char *field=out; +#endif + +printf("\r\nDEBUG HTTPRPC::clean() IN=:%s:\r\n",str); + while (*in) { +#if HTTPRPC_USE_URI_FIELDS + // Check if URI has query part + // in form "/rpc/obj/method?arg1=val1&arg2=val2&arg3=val3" + if (!inquotes && !cantquery && !hasquery && *in == '?') { + hasquery = true; + *out = ' '; out++; // delimit base URI part + infield = true; in++; field=in; continue; + // New field started. Do nothing yet + } + // Check if URI with query part is delimited + if (!inquotes && !infield && hasquery && *in == '&') { + *out = ' '; out++; // delimit current arg + infield = true; in++; field=in; continue; + // New field started } - if(*str==','||*str=='+'||*str=='=') { - *str = ' '; + if (infield) { + // Process the query - skip till '=' + // Also check if it is in form "/rpc/obj/method?val1&val2&val3" + if (!inquotes && *in == '&') { + // modified query - catch up + while (field<in) { + *out = *field; + if (*field=='%' && is_hex(*(field+1)) && is_hex(*(field+2)) ) { + *out = hex_byte(++field); + field++; // field is incremented by 2 total + } + if (!backslash && *out == '"') { inquotes = !inquotes; } + backslash = inquotes && !backslash && (*out == '\\'); + + out++; + field++; + } + + *out = ' '; out++; // delimit current arg + infield = true; in++; field=in; continue; + // New field started + } else + if (!inquotes && *in == '=') { + infield = false; + *in = '\0'; // this will mark the field name +printf(" - field: %s\r\n", field); +// FIXME: here we have a field/arg name. Can we use it to reorder the arguments for the rpc? + + } else { + // Keep tracking quotes + char tmp = *in; + if (*in=='%' && is_hex(*(in+1)) && is_hex(*(in+2)) ) { + tmp = hex_byte(++in); + in++; // in is incremented by 2 total + } + if (!backslash && tmp == '"') { inquotes = !inquotes; } + backslash = inquotes && !backslash && (tmp == '\\'); + } + } else +#endif // HTTPRPC_USE_URI_FIELDS + { + // Keep processing the stream + *out = *in; + + if (*in=='%' && is_hex(*(in+1)) && is_hex(*(in+2)) ) { + *out = hex_byte(++in); + in++; // in is incremented by 2 total + cantquery = !hasquery; // any %-encoded before '?' means it can't be a query + } else + if (!inquotes && !hasquery && (*in==',' || *in=='+' || *in=='=')) { + *out = ' '; +// cantquery = !hasquery; // any non-query delimiter disallows URI query + } + if (!backslash && *out == '"') { inquotes = !inquotes; } + backslash = inquotes && !backslash && (*out == '\\'); + + out++; + } + + in++; + } // while + +#if HTTPRPC_USE_URI_FIELDS + if (infield) { + // modified query last arg - catch up + while (field < in) { + *out = *field; + if (*field=='%' && is_hex(*(field+1)) && is_hex(*(field+2)) ) { + *out = hex_byte(++field); + field++; // field is incremented by 2 total + } + if (!backslash && *out == '"') { inquotes = !inquotes; } + backslash = inquotes && !backslash && (*out == '\\'); + + out++; + field++; } } +#endif // HTTPRPC_USE_URI_FIELDS + + hasquery = cantquery; // only removes compiler warning + *out = '\0'; + +// out = _buf; + out = str; +printf("DEBUG HTTPRPC::clean() OUT=:%s:\r\n", out); + return out; } }; #endif
--- a/lwip/SNTPClient/DstZones.h Fri Jan 08 00:28:14 2010 +0000 +++ b/lwip/SNTPClient/DstZones.h Tue Jan 12 07:41:55 2010 +0000 @@ -23,14 +23,14 @@ // USA: 3600; 2, Second SUN, March; 2, First SUN, November _( DST_USA, NULL, 0, 3600, 2, 2, 0, 2, 2, 1, 0, 10 ) - // USA: 3600; 2, First SUN, April; 2, Last SUN, October + // USA: 3600; 2, First SUN, April; 2, Last SUN, October (Pre-2007) _( DST_USA_06, NULL, 0, 3600, 2, 1, 0, 3, 2, 0, 0, 9 ) // EU: 3600; 1GMT, Last SUN, March; 1GMT, Last SUN, October _( DST_EU_GMT, NULL, 1, 3600, 1, 0, 0, 2, 1, 0, 0, 9 ) - // Just for test -_( DST_TEST, NULL, 0, 3600, 18, 1, 2, 0, 12, 1, 4, 0 ) +// // Just for test +//_( DST_TEST, NULL, 0, 3600, 18, 1, 2, 0, 12, 1, 4, 0 ) #undef _
--- a/lwip/SNTPClient/SNTPClient.cpp Fri Jan 08 00:28:14 2010 +0000 +++ b/lwip/SNTPClient/SNTPClient.cpp Tue Jan 12 07:41:55 2010 +0000 @@ -76,8 +76,8 @@ extern "C" { #endif tDST_ZONE gSntpDstZone = DST_NONE; // DST zone - rule selector -unsigned int gSntpRecvTimeout_ms = 3000; // 3 sec; SNTP_RECV_TIMEOUT -unsigned int gSntpUpdateDelay_ms = 3600000; // 1 hour; SNTP_UPDATE_DELAY +unsigned int gSntpRecvTimeout_s = 3; // 3 sec; SNTP_RECV_TIMEOUT +unsigned int gSntpUpdateDelay_s = 3600; // 1 hour; SNTP_UPDATE_DELAY signed int gSntpTimezone = 0*3600; // seconds from UTC to local time signed int gSntpDST = 0*3600; // seconds from UTC to local time bool gSntpRtcUtc = false; // true to keep RTC in UTC, false to keep in local time @@ -525,7 +525,7 @@ static void (*sntp_addresses_free)(void*) = NULL; static Timeout _sntp_timer1; static Timeout _sntp_timer2; -void sntp_sys_timeout(u32_t timeout_ms, void (*func)(void *arg), void *arg) { +void sntp_sys_timeout(u32_t timeout_s, void (*func)(void *arg), void *arg) { // all we really need to track is only 2 functions: sntp_request, sntp_try_next_server Timeout *t = NULL; if (func == &sntp_request) { @@ -537,7 +537,7 @@ } if (t) { t->detach(); - t->attach((void(*)(void))func, 0.001*timeout_ms); + t->attach((void(*)(void))func, 1.0*timeout_s); // Another shortcut - we have no arg to pass, so just typecast the func. } } @@ -574,8 +574,8 @@ } } -void SNTPSetRecvTimeout(unsigned int val_ms) { gSntpRecvTimeout_ms = val_ms; } -void SNTPSetUpdateDelay(unsigned int val_ms) { gSntpUpdateDelay_ms = val_ms; } +void SNTPSetRecvTimeout(unsigned int val_s) { gSntpRecvTimeout_s = val_s; } +void SNTPSetUpdateDelay(unsigned int val_s) { gSntpUpdateDelay_s = val_s; } void SNTPSetTimezone(float hours_from_utc, bool adjust_clock) { if (adjust_clock && !gSntpRtcUtc) { time_t seconds = time(NULL); @@ -672,8 +672,8 @@ fprintf(f, "Timezone=%0.1f" CRLF, gSntpTimezone / 3600.0); fprintf(f, "DstZone=%d" CRLF, gSntpDstZone); fprintf(f, "# %s" CRLF, SNTPDstZoneName(gSntpDstZone)); - fprintf(f, "UpdateDelay=%d" CRLF, gSntpUpdateDelay_ms); - fprintf(f, "RecvTimeout=%d" CRLF, gSntpRecvTimeout_ms); + fprintf(f, "UpdateDelay=%d" CRLF, gSntpUpdateDelay_s); + fprintf(f, "RecvTimeout=%d" CRLF, gSntpRecvTimeout_s); fprintf(f, CRLF "##END" CRLF); } @@ -733,9 +733,9 @@ if (0 == strncmp(buf1, "Timezone", sizeof("Timezone")-1)) { gSntpTimezone = strtod(buf2, &buf2) * 3600; } else if (0 == strncmp(buf1, "UpdateDelay", sizeof("UpdateDelay")-1)) { - gSntpUpdateDelay_ms = strtoul(buf2, &buf2, 10); + gSntpUpdateDelay_s = strtoul(buf2, &buf2, 10); } else if (0 == strncmp(buf1, "RecvTimeout", sizeof("RecvTimeout")-1)) { - gSntpRecvTimeout_ms = strtoul(buf2, &buf2, 10); + gSntpRecvTimeout_s = strtoul(buf2, &buf2, 10); } else if (0 == strncmp(buf1, "RtcUtc", sizeof("RtcUtc")-1)) { gSntpRtcUtc = (bool)strtol(buf2, &buf2, 10); } else if (0 == strncmp(buf1, "DstZone", sizeof("DstZone")-1)) { @@ -772,8 +772,8 @@ #endif // SNTPv4 RFC 4330 enforces a minimum update time of 15 seconds - if (gSntpUpdateDelay_ms < 15000) { - gSntpUpdateDelay_ms = 15000; + if (gSntpUpdateDelay_s < 15) { + gSntpUpdateDelay_s = 15; } gSntpRunning = true;
--- a/lwip/SNTPClient/SNTPClient.h Fri Jan 08 00:28:14 2010 +0000 +++ b/lwip/SNTPClient/SNTPClient.h Tue Jan 12 07:41:55 2010 +0000 @@ -21,8 +21,8 @@ void SNTPSetDstZone(tDST_ZONE zone, bool adjust_clock=false); const char *SNTPDstZoneName(tDST_ZONE zone); -void SNTPSetRecvTimeout(unsigned int val_ms); -void SNTPSetUpdateDelay(unsigned int val_ms); +void SNTPSetRecvTimeout(unsigned int val_s); +void SNTPSetUpdateDelay(unsigned int val_s); void SNTPSetTimezone(float hours_from_utc, bool adjust_clock=false); void SNTPSetDST(float hours_from_utc, bool adjust_clock=false); int SNTPSetAddresses(const char* server_addresses[], int count, void (*p_free)(void*));
--- a/myrpc.cpp Fri Jan 08 00:28:14 2010 +0000 +++ b/myrpc.cpp Tue Jan 12 07:41:55 2010 +0000 @@ -32,6 +32,12 @@ } } +char *myrpc::echo(const char * in) { +printf("DEBUG myrpc::echo() IN=%s\r\n",in); + sprintf(_buffer, "%s", in); + return _buffer; +} + void myrpc::settime(const char *t) { time_t seconds = time(NULL); if (seconds == (unsigned)-1 || seconds == 0) { @@ -58,6 +64,7 @@ static const rpc_method rpc_methods[] = { { "debug", rpc_method_caller<myrpc, int, &myrpc::debug> }, { "blink", rpc_method_caller<myrpc, int, &myrpc::blink> }, + { "echo", rpc_method_caller<char *, myrpc, const char *, &myrpc::echo> }, { "settime", rpc_method_caller<myrpc, const char *, &myrpc::settime> }, { "gettime", rpc_method_caller<char *, myrpc, const char *, &myrpc::gettime> }, RPC_METHOD_SUPER(Base)
--- a/myrpc.h Fri Jan 08 00:28:14 2010 +0000 +++ b/myrpc.h Tue Jan 12 07:41:55 2010 +0000 @@ -16,6 +16,7 @@ myrpc(PinName pin, const char* name = NULL); void debug(int val); void blink(int n); + char * echo(const char *); void settime(const char *t); char *gettime(const char *fmt); @@ -26,7 +27,7 @@ protected: DigitalOut _pin; - char _buffer[64]; // String buffer + char _buffer[256]; // String buffer }; } // namespace mbed