LRSD stephane / Mbed 2 deprecated WEBserver0-lrsd

Dependencies:   mbed

Committer:
geiineuville
Date:
Fri Sep 02 08:36:24 2011 +0000
Revision:
0:441400ffd086
V0

Who changed what in which revision?

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