LRSD stephane / Mbed 2 deprecated WEBserverv3

Dependencies:   mbed

Committer:
geiineuville
Date:
Thu Sep 08 08:57:21 2011 +0000
Revision:
0:9cf1d79ebe04
v0 v1 v2   \"v3\"

Who changed what in which revision?

UserRevisionLine numberNew contents of line
geiineuville 0:9cf1d79ebe04 1 // HTTPRPC.h
geiineuville 0:9cf1d79ebe04 2 // Modified by iva2k
geiineuville 0:9cf1d79ebe04 3 // Improved URL string handling
geiineuville 0:9cf1d79ebe04 4 //
geiineuville 0:9cf1d79ebe04 5
geiineuville 0:9cf1d79ebe04 6 #ifndef HTTPRPC_H
geiineuville 0:9cf1d79ebe04 7 #define HTTPRPC_H
geiineuville 0:9cf1d79ebe04 8
geiineuville 0:9cf1d79ebe04 9 #include "HTTPServer.h"
geiineuville 0:9cf1d79ebe04 10 #include "platform.h"
geiineuville 0:9cf1d79ebe04 11 #ifdef MBED_RPC
geiineuville 0:9cf1d79ebe04 12 #include "rpc.h"
geiineuville 0:9cf1d79ebe04 13
geiineuville 0:9cf1d79ebe04 14 #ifndef HTTPRPC_USE_URI_FIELDS
geiineuville 0:9cf1d79ebe04 15 #define HTTPRPC_USE_URI_FIELDS 1
geiineuville 0:9cf1d79ebe04 16 #endif
geiineuville 0:9cf1d79ebe04 17
geiineuville 0:9cf1d79ebe04 18 /**
geiineuville 0:9cf1d79ebe04 19 * A datastorage helper for the HTTPRPC class
geiineuville 0:9cf1d79ebe04 20 */
geiineuville 0:9cf1d79ebe04 21 class HTTPRPCData : public HTTPData {
geiineuville 0:9cf1d79ebe04 22 public: char result[255];
geiineuville 0:9cf1d79ebe04 23 };
geiineuville 0:9cf1d79ebe04 24
geiineuville 0:9cf1d79ebe04 25 /**
geiineuville 0:9cf1d79ebe04 26 * Thsi class enables you to make rpc calls to your mbed.
geiineuville 0:9cf1d79ebe04 27 * Furthermore it is a good example how to write a HTTPHandler for small data chunks.
geiineuville 0:9cf1d79ebe04 28 */
geiineuville 0:9cf1d79ebe04 29 class HTTPRPC : public HTTPHandler {
geiineuville 0:9cf1d79ebe04 30 public:
geiineuville 0:9cf1d79ebe04 31 /**
geiineuville 0:9cf1d79ebe04 32 * We have to know the prefix for the RPCHandler.
geiineuville 0:9cf1d79ebe04 33 * A good default choice is /rpc so we made this default.
geiineuville 0:9cf1d79ebe04 34 */
geiineuville 0:9cf1d79ebe04 35 HTTPRPC(const char *path = "/rpc") : HTTPHandler(path) {}
geiineuville 0:9cf1d79ebe04 36 HTTPRPC(HTTPServer *server, const char *path = "/rpc") : HTTPHandler(path) { server->addHandler(this); }
geiineuville 0:9cf1d79ebe04 37
geiineuville 0:9cf1d79ebe04 38 private:
geiineuville 0:9cf1d79ebe04 39 /**
geiineuville 0:9cf1d79ebe04 40 * If you need some Headerfeelds you have tor register the feelds here.
geiineuville 0:9cf1d79ebe04 41 */
geiineuville 0:9cf1d79ebe04 42 // virtual void reg(HTTPServer *svr) {
geiineuville 0:9cf1d79ebe04 43 // svr->registerField("Content-Length");
geiineuville 0:9cf1d79ebe04 44 // }
geiineuville 0:9cf1d79ebe04 45
geiineuville 0:9cf1d79ebe04 46 /**
geiineuville 0:9cf1d79ebe04 47 * If a new RPCRequest Header is complete received the server will call this function.
geiineuville 0:9cf1d79ebe04 48 * This is the right place for preparing our datastructures.
geiineuville 0:9cf1d79ebe04 49 * Furthermore we will execute the rpc call and store the anwere.
geiineuville 0:9cf1d79ebe04 50 * But we will not send a response. This will be hapen in the send method.
geiineuville 0:9cf1d79ebe04 51 */
geiineuville 0:9cf1d79ebe04 52 virtual HTTPStatus init(HTTPConnection *con) const {
geiineuville 0:9cf1d79ebe04 53 HTTPRPCData *data = new HTTPRPCData();
geiineuville 0:9cf1d79ebe04 54 con->data = data;
geiineuville 0:9cf1d79ebe04 55 char *query = con->getURL()+strlen(_prefix);
geiineuville 0:9cf1d79ebe04 56 query = clean(query);
geiineuville 0:9cf1d79ebe04 57 rpc(query, data->result);
geiineuville 0:9cf1d79ebe04 58
geiineuville 0:9cf1d79ebe04 59 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";
geiineuville 0:9cf1d79ebe04 60 char *old = (char *)con->getHeaderFields();
geiineuville 0:9cf1d79ebe04 61 int oldlen = strlen(old);
geiineuville 0:9cf1d79ebe04 62 int atrlen = strlen(nfields);
geiineuville 0:9cf1d79ebe04 63 char *fields = new char[atrlen+oldlen+3];
geiineuville 0:9cf1d79ebe04 64 strcpy(fields,old);
geiineuville 0:9cf1d79ebe04 65 fields[oldlen+0] = '\r';
geiineuville 0:9cf1d79ebe04 66 fields[oldlen+1] = '\n';
geiineuville 0:9cf1d79ebe04 67 strcpy(&fields[oldlen+2], nfields);
geiineuville 0:9cf1d79ebe04 68 fields[atrlen+2+oldlen] = '\0';
geiineuville 0:9cf1d79ebe04 69 con->setHeaderFields(fields);
geiineuville 0:9cf1d79ebe04 70 if(*old) {
geiineuville 0:9cf1d79ebe04 71 delete old;
geiineuville 0:9cf1d79ebe04 72 }
geiineuville 0:9cf1d79ebe04 73
geiineuville 0:9cf1d79ebe04 74 con->setLength(strlen(data->result));
geiineuville 0:9cf1d79ebe04 75 return HTTP_OK;
geiineuville 0:9cf1d79ebe04 76 }
geiineuville 0:9cf1d79ebe04 77
geiineuville 0:9cf1d79ebe04 78 /**
geiineuville 0:9cf1d79ebe04 79 * If we got an POST request the send method will not be executed.
geiineuville 0:9cf1d79ebe04 80 * If we want to send data we have to trigger it the first time by ourself.
geiineuville 0:9cf1d79ebe04 81 * So we execute the send method.
geiineuville 0:9cf1d79ebe04 82 *
geiineuville 0:9cf1d79ebe04 83 * If the rpc call is the content of the POST body we would not be able to execute it.
geiineuville 0:9cf1d79ebe04 84 * Were parsing only the URL.
geiineuville 0:9cf1d79ebe04 85 */
geiineuville 0:9cf1d79ebe04 86 virtual HTTPHandle data(HTTPConnection *con, void *, int) const {
geiineuville 0:9cf1d79ebe04 87 return send(con, con->sndbuf());
geiineuville 0:9cf1d79ebe04 88 }
geiineuville 0:9cf1d79ebe04 89
geiineuville 0:9cf1d79ebe04 90 /**
geiineuville 0:9cf1d79ebe04 91 * Send the result back to the client.
geiineuville 0:9cf1d79ebe04 92 * If we have not enought space wait for next time.
geiineuville 0:9cf1d79ebe04 93 */
geiineuville 0:9cf1d79ebe04 94 virtual HTTPHandle send(HTTPConnection *con, int maximum) const {
geiineuville 0:9cf1d79ebe04 95 HTTPRPCData *data = static_cast<HTTPRPCData *>(con->data);
geiineuville 0:9cf1d79ebe04 96 if(maximum>64) {
geiineuville 0:9cf1d79ebe04 97 con->write(data->result, con->getLength());
geiineuville 0:9cf1d79ebe04 98 return HTTP_SuccessEnded;
geiineuville 0:9cf1d79ebe04 99 } else {
geiineuville 0:9cf1d79ebe04 100 // To less memory.
geiineuville 0:9cf1d79ebe04 101 return HTTP_SenderMemory;
geiineuville 0:9cf1d79ebe04 102 }
geiineuville 0:9cf1d79ebe04 103 }
geiineuville 0:9cf1d79ebe04 104
geiineuville 0:9cf1d79ebe04 105 inline bool is_hex(const char a) const {
geiineuville 0:9cf1d79ebe04 106 return (a>='0' && a<='9') || (a>='A' && a<='F') || (a>='a' && a<='f');
geiineuville 0:9cf1d79ebe04 107 }
geiineuville 0:9cf1d79ebe04 108 inline char hex_nib(const char a) const {
geiineuville 0:9cf1d79ebe04 109 return 0xf & (
geiineuville 0:9cf1d79ebe04 110 (a>='0' && a<='9') ? (a-'0' ) :
geiineuville 0:9cf1d79ebe04 111 (a>='A' && a<='F') ? (a-'A'+10) :
geiineuville 0:9cf1d79ebe04 112 (a>='a' && a<='f') ? (a-'a'+10) : 0
geiineuville 0:9cf1d79ebe04 113 );
geiineuville 0:9cf1d79ebe04 114 }
geiineuville 0:9cf1d79ebe04 115 inline char hex_byte(const char *str) const {
geiineuville 0:9cf1d79ebe04 116 return (hex_nib(*str) << 4) | hex_nib(*(str+1));
geiineuville 0:9cf1d79ebe04 117 }
geiineuville 0:9cf1d79ebe04 118 /**
geiineuville 0:9cf1d79ebe04 119 * To reduce memory usage we sodify the URL directly
geiineuville 0:9cf1d79ebe04 120 * and replace '%20',',','+','=' with spaces.
geiineuville 0:9cf1d79ebe04 121 */
geiineuville 0:9cf1d79ebe04 122 // mutable char _buf[1024];
geiineuville 0:9cf1d79ebe04 123 inline char *clean(char *str) const {
geiineuville 0:9cf1d79ebe04 124 char *in = str;
geiineuville 0:9cf1d79ebe04 125 // char *out = _buf;
geiineuville 0:9cf1d79ebe04 126 char *out = str; // this will do conversions in-place.
geiineuville 0:9cf1d79ebe04 127 bool inquotes=false;
geiineuville 0:9cf1d79ebe04 128 bool backslash=false;
geiineuville 0:9cf1d79ebe04 129 bool hasquery=false;
geiineuville 0:9cf1d79ebe04 130 bool cantquery=false;
geiineuville 0:9cf1d79ebe04 131 // cantquery=true will indicate that the URI already has symbols
geiineuville 0:9cf1d79ebe04 132 // incompatible with query, so it disables checking for query.
geiineuville 0:9cf1d79ebe04 133 #if HTTPRPC_USE_URI_FIELDS
geiineuville 0:9cf1d79ebe04 134 bool infield=false;
geiineuville 0:9cf1d79ebe04 135 // bool rpcquery=false;
geiineuville 0:9cf1d79ebe04 136 char *field=out;
geiineuville 0:9cf1d79ebe04 137 #endif
geiineuville 0:9cf1d79ebe04 138
geiineuville 0:9cf1d79ebe04 139 printf("\r\nDEBUG HTTPRPC::clean() IN=:%s:\r\n",str);
geiineuville 0:9cf1d79ebe04 140 while (*in) {
geiineuville 0:9cf1d79ebe04 141 #if HTTPRPC_USE_URI_FIELDS
geiineuville 0:9cf1d79ebe04 142 // Check if URI has query part
geiineuville 0:9cf1d79ebe04 143 // in form "/rpc/obj/method?arg1=val1&arg2=val2&arg3=val3"
geiineuville 0:9cf1d79ebe04 144 if (!inquotes && !cantquery && !hasquery && *in == '?') {
geiineuville 0:9cf1d79ebe04 145 hasquery = true;
geiineuville 0:9cf1d79ebe04 146 *out = ' '; out++; // delimit base URI part
geiineuville 0:9cf1d79ebe04 147 infield = true; in++; field=in; continue;
geiineuville 0:9cf1d79ebe04 148 // New field started. Do nothing yet
geiineuville 0:9cf1d79ebe04 149 }
geiineuville 0:9cf1d79ebe04 150 // Check if URI with query part is delimited
geiineuville 0:9cf1d79ebe04 151 if (!inquotes && !infield && hasquery && *in == '&') {
geiineuville 0:9cf1d79ebe04 152 *out = ' '; out++; // delimit current arg
geiineuville 0:9cf1d79ebe04 153 infield = true; in++; field=in; continue;
geiineuville 0:9cf1d79ebe04 154 // New field started
geiineuville 0:9cf1d79ebe04 155 }
geiineuville 0:9cf1d79ebe04 156 if (infield) {
geiineuville 0:9cf1d79ebe04 157 // Process the query - skip till '='
geiineuville 0:9cf1d79ebe04 158 // Also check if it is in form "/rpc/obj/method?val1&val2&val3"
geiineuville 0:9cf1d79ebe04 159 if (!inquotes && *in == '&') {
geiineuville 0:9cf1d79ebe04 160 // modified query - catch up
geiineuville 0:9cf1d79ebe04 161 while (field<in) {
geiineuville 0:9cf1d79ebe04 162 *out = *field;
geiineuville 0:9cf1d79ebe04 163 if (*field=='%' && is_hex(*(field+1)) && is_hex(*(field+2)) ) {
geiineuville 0:9cf1d79ebe04 164 *out = hex_byte(++field);
geiineuville 0:9cf1d79ebe04 165 field++; // field is incremented by 2 total
geiineuville 0:9cf1d79ebe04 166 }
geiineuville 0:9cf1d79ebe04 167 if (!backslash && *out == '"') { inquotes = !inquotes; }
geiineuville 0:9cf1d79ebe04 168 backslash = inquotes && !backslash && (*out == '\\');
geiineuville 0:9cf1d79ebe04 169
geiineuville 0:9cf1d79ebe04 170 out++;
geiineuville 0:9cf1d79ebe04 171 field++;
geiineuville 0:9cf1d79ebe04 172 }
geiineuville 0:9cf1d79ebe04 173
geiineuville 0:9cf1d79ebe04 174 *out = ' '; out++; // delimit current arg
geiineuville 0:9cf1d79ebe04 175 infield = true; in++; field=in; continue;
geiineuville 0:9cf1d79ebe04 176 // New field started
geiineuville 0:9cf1d79ebe04 177 } else
geiineuville 0:9cf1d79ebe04 178 if (!inquotes && *in == '=') {
geiineuville 0:9cf1d79ebe04 179 infield = false;
geiineuville 0:9cf1d79ebe04 180 *in = '\0'; // this will mark the field name
geiineuville 0:9cf1d79ebe04 181 printf(" - field: %s\r\n", field);
geiineuville 0:9cf1d79ebe04 182 // FIXME: here we have a field/arg name. Can we use it to reorder the arguments for the rpc?
geiineuville 0:9cf1d79ebe04 183
geiineuville 0:9cf1d79ebe04 184 } else {
geiineuville 0:9cf1d79ebe04 185 // Keep tracking quotes
geiineuville 0:9cf1d79ebe04 186 char tmp = *in;
geiineuville 0:9cf1d79ebe04 187 if (*in=='%' && is_hex(*(in+1)) && is_hex(*(in+2)) ) {
geiineuville 0:9cf1d79ebe04 188 tmp = hex_byte(++in);
geiineuville 0:9cf1d79ebe04 189 in++; // in is incremented by 2 total
geiineuville 0:9cf1d79ebe04 190 }
geiineuville 0:9cf1d79ebe04 191 if (!backslash && tmp == '"') { inquotes = !inquotes; }
geiineuville 0:9cf1d79ebe04 192 backslash = inquotes && !backslash && (tmp == '\\');
geiineuville 0:9cf1d79ebe04 193 }
geiineuville 0:9cf1d79ebe04 194 } else
geiineuville 0:9cf1d79ebe04 195 #endif // HTTPRPC_USE_URI_FIELDS
geiineuville 0:9cf1d79ebe04 196 {
geiineuville 0:9cf1d79ebe04 197 // Keep processing the stream
geiineuville 0:9cf1d79ebe04 198 *out = *in;
geiineuville 0:9cf1d79ebe04 199
geiineuville 0:9cf1d79ebe04 200 if (*in=='%' && is_hex(*(in+1)) && is_hex(*(in+2)) ) {
geiineuville 0:9cf1d79ebe04 201 *out = hex_byte(++in);
geiineuville 0:9cf1d79ebe04 202 in++; // in is incremented by 2 total
geiineuville 0:9cf1d79ebe04 203 cantquery = !hasquery; // any %-encoded before '?' means it can't be a query
geiineuville 0:9cf1d79ebe04 204 } else
geiineuville 0:9cf1d79ebe04 205 if (!inquotes && !hasquery && (*in==',' || *in=='+' || *in=='=')) {
geiineuville 0:9cf1d79ebe04 206 *out = ' ';
geiineuville 0:9cf1d79ebe04 207 // cantquery = !hasquery; // any non-query delimiter disallows URI query
geiineuville 0:9cf1d79ebe04 208 }
geiineuville 0:9cf1d79ebe04 209 if (!backslash && *out == '"') { inquotes = !inquotes; }
geiineuville 0:9cf1d79ebe04 210 backslash = inquotes && !backslash && (*out == '\\');
geiineuville 0:9cf1d79ebe04 211
geiineuville 0:9cf1d79ebe04 212 out++;
geiineuville 0:9cf1d79ebe04 213 }
geiineuville 0:9cf1d79ebe04 214
geiineuville 0:9cf1d79ebe04 215 in++;
geiineuville 0:9cf1d79ebe04 216 } // while
geiineuville 0:9cf1d79ebe04 217
geiineuville 0:9cf1d79ebe04 218 #if HTTPRPC_USE_URI_FIELDS
geiineuville 0:9cf1d79ebe04 219 if (infield) {
geiineuville 0:9cf1d79ebe04 220 // modified query last arg - catch up
geiineuville 0:9cf1d79ebe04 221 while (field < in) {
geiineuville 0:9cf1d79ebe04 222 *out = *field;
geiineuville 0:9cf1d79ebe04 223 if (*field=='%' && is_hex(*(field+1)) && is_hex(*(field+2)) ) {
geiineuville 0:9cf1d79ebe04 224 *out = hex_byte(++field);
geiineuville 0:9cf1d79ebe04 225 field++; // field is incremented by 2 total
geiineuville 0:9cf1d79ebe04 226 }
geiineuville 0:9cf1d79ebe04 227 if (!backslash && *out == '"') { inquotes = !inquotes; }
geiineuville 0:9cf1d79ebe04 228 backslash = inquotes && !backslash && (*out == '\\');
geiineuville 0:9cf1d79ebe04 229
geiineuville 0:9cf1d79ebe04 230 out++;
geiineuville 0:9cf1d79ebe04 231 field++;
geiineuville 0:9cf1d79ebe04 232 }
geiineuville 0:9cf1d79ebe04 233 }
geiineuville 0:9cf1d79ebe04 234 #endif // HTTPRPC_USE_URI_FIELDS
geiineuville 0:9cf1d79ebe04 235
geiineuville 0:9cf1d79ebe04 236 hasquery = cantquery; // only removes compiler warning
geiineuville 0:9cf1d79ebe04 237 *out = '\0';
geiineuville 0:9cf1d79ebe04 238
geiineuville 0:9cf1d79ebe04 239 // out = _buf;
geiineuville 0:9cf1d79ebe04 240 out = str;
geiineuville 0:9cf1d79ebe04 241 printf("DEBUG HTTPRPC::clean() OUT=:%s:\r\n", out);
geiineuville 0:9cf1d79ebe04 242 return out;
geiineuville 0:9cf1d79ebe04 243 }
geiineuville 0:9cf1d79ebe04 244 };
geiineuville 0:9cf1d79ebe04 245 #endif
geiineuville 0:9cf1d79ebe04 246
geiineuville 0:9cf1d79ebe04 247 #endif