LRSD stephane / Mbed 2 deprecated WEBserverv4

Dependencies:   mbed

Committer:
geiineuville
Date:
Thu Sep 22 15:59:17 2011 +0000
Revision:
0:3c32eeb9292a
V4

Who changed what in which revision?

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