Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Diff: lwip/HTTPServer/HTTPRPC.h
- Revision:
- 0:3c32eeb9292a
diff -r 000000000000 -r 3c32eeb9292a lwip/HTTPServer/HTTPRPC.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwip/HTTPServer/HTTPRPC.h Thu Sep 22 15:59:17 2011 +0000
@@ -0,0 +1,247 @@
+// HTTPRPC.h
+// Modified by iva2k
+// Improved URL string handling
+//
+
+#ifndef HTTPRPC_H
+#define HTTPRPC_H
+
+#include "HTTPServer.h"
+#include "platform.h"
+#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
+ */
+class HTTPRPCData : public HTTPData {
+ public: char result[255];
+};
+
+/**
+ * Thsi class enables you to make rpc calls to your mbed.
+ * Furthermore it is a good example how to write a HTTPHandler for small data chunks.
+ */
+class HTTPRPC : public HTTPHandler {
+ public:
+ /**
+ * We have to know the prefix for the RPCHandler.
+ * A good default choice is /rpc so we made this default.
+ */
+ 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.
+ */
+// virtual void reg(HTTPServer *svr) {
+// svr->registerField("Content-Length");
+// }
+
+ /**
+ * If a new RPCRequest Header is complete received the server will call this function.
+ * This is the right place for preparing our datastructures.
+ * Furthermore we will execute the rpc call and store the anwere.
+ * But we will not send a response. This will be hapen in the send method.
+ */
+ virtual HTTPStatus init(HTTPConnection *con) const {
+ HTTPRPCData *data = new HTTPRPCData();
+ con->data = data;
+ char *query = con->getURL()+strlen(_prefix);
+ 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";
+ char *old = (char *)con->getHeaderFields();
+ int oldlen = strlen(old);
+ int atrlen = strlen(nfields);
+ char *fields = new char[atrlen+oldlen+3];
+ strcpy(fields,old);
+ fields[oldlen+0] = '\r';
+ fields[oldlen+1] = '\n';
+ strcpy(&fields[oldlen+2], nfields);
+ fields[atrlen+2+oldlen] = '\0';
+ con->setHeaderFields(fields);
+ if(*old) {
+ delete old;
+ }
+
+ con->setLength(strlen(data->result));
+ return HTTP_OK;
+ }
+
+ /**
+ * If we got an POST request the send method will not be executed.
+ * If we want to send data we have to trigger it the first time by ourself.
+ * So we execute the send method.
+ *
+ * If the rpc call is the content of the POST body we would not be able to execute it.
+ * Were parsing only the URL.
+ */
+ virtual HTTPHandle data(HTTPConnection *con, void *, int) const {
+ return send(con, con->sndbuf());
+ }
+
+ /**
+ * Send the result back to the client.
+ * 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);
+ if(maximum>64) {
+ con->write(data->result, con->getLength());
+ return HTTP_SuccessEnded;
+ } else {
+ // To less memory.
+ return HTTP_SenderMemory;
+ }
+ }
+
+ 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
+ * and replace '%20',',','+','=' with spaces.
+ */
+// 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 (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
+
+#endif