LRSD stephane / Mbed 2 deprecated WEBserverv1

Dependencies:   mbed

Committer:
geiineuville
Date:
Sat Sep 03 09:42:32 2011 +0000
Revision:
0:4570f87afab6
v1

Who changed what in which revision?

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