Mitesh Patel / Mbed 2 deprecated camera_online_server

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers HTTPRPC.h Source File

HTTPRPC.h

00001 // HTTPRPC.h
00002 // Modified by iva2k
00003 // Improved URL string handling
00004 //
00005 
00006 #ifndef HTTPRPC_H
00007 #define HTTPRPC_H
00008 
00009 #include "HTTPServer.h"
00010 #include "platform.h"
00011 #ifdef MBED_RPC
00012 #include "rpc.h"
00013 
00014 #ifndef HTTPRPC_USE_URI_FIELDS
00015 #define HTTPRPC_USE_URI_FIELDS 1
00016 #endif
00017 
00018 /**
00019  * A datastorage helper for the HTTPRPC class
00020  */
00021 class HTTPRPCData : public HTTPData {
00022   public: char result[255];
00023 };
00024 
00025 /**
00026  * Thsi class enables you to make rpc calls to your mbed.
00027  * Furthermore it is a good example how to write a HTTPHandler for small data chunks.
00028  */
00029 class HTTPRPC : public HTTPHandler {
00030   public:
00031     /**
00032      * We have to know the prefix for the RPCHandler.
00033      * A good default choice is /rpc so we made this default.
00034      */
00035     HTTPRPC(const char *path = "/rpc") : HTTPHandler(path) {}
00036     HTTPRPC(HTTPServer *server, const char *path = "/rpc") : HTTPHandler(path) { server->addHandler(this); }
00037 
00038   private:
00039     /**
00040      * If you need some Headerfeelds you have tor register the feelds here.
00041      */
00042 //    virtual void reg(HTTPServer *svr) {
00043 //      svr->registerField("Content-Length");
00044 //    }
00045 
00046     /**
00047      * If a new RPCRequest Header is complete received the server will call this function.
00048      * This is the right place for preparing our datastructures.
00049      * Furthermore we will execute the rpc call and store the anwere.
00050      * But we will not send a response. This will be hapen in the send method.
00051      */
00052     virtual HTTPStatus init(HTTPConnection *con) const {
00053       HTTPRPCData *data = new HTTPRPCData();
00054       con->data = data;
00055       char *query = con->getURL()+strlen(_prefix);
00056       query = clean(query);
00057       rpc(query, data->result);
00058 
00059       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";
00060       char *old = (char *)con->getHeaderFields();
00061       int oldlen = strlen(old);
00062       int atrlen = strlen(nfields);
00063       char *fields = new char[atrlen+oldlen+3];
00064       strcpy(fields,old);
00065       fields[oldlen+0] = '\r';
00066       fields[oldlen+1] = '\n';
00067       strcpy(&fields[oldlen+2], nfields);
00068       fields[atrlen+2+oldlen] = '\0';
00069       con->setHeaderFields(fields);
00070       if(*old) {
00071         delete old;
00072       }
00073 
00074       con->setLength(strlen(data->result));
00075       return HTTP_OK;
00076     }
00077 
00078     /**
00079      * If we got an POST request the send method will not be executed.
00080      * If we want to send data we have to trigger it the first time by ourself.
00081      * So we execute the send method.
00082      *
00083      * If the rpc call is the content of the POST body we would not be able to execute it.
00084      * Were parsing only the URL.
00085      */
00086     virtual HTTPHandle data(HTTPConnection *con, void *, int) const {
00087       return send(con, con->sndbuf());
00088     }
00089 
00090     /**
00091      * Send the result back to the client.
00092      * If we have not enought space wait for next time.
00093      */
00094     virtual HTTPHandle send(HTTPConnection *con, int maximum) const {
00095       HTTPRPCData *data = static_cast<HTTPRPCData *>(con->data);
00096       if(maximum>64) {
00097         con->write(data->result, con->getLength());
00098         return HTTP_SuccessEnded;
00099       } else {
00100         // To less memory.
00101         return HTTP_SenderMemory;
00102       }
00103     }
00104 
00105     inline bool is_hex(const char a) const {
00106         return (a>='0' && a<='9') || (a>='A' && a<='F') || (a>='a' && a<='f');
00107     }
00108     inline char hex_nib(const char a) const {
00109         return 0xf & (
00110           (a>='0' && a<='9') ? (a-'0'   ) :
00111           (a>='A' && a<='F') ? (a-'A'+10) :
00112           (a>='a' && a<='f') ? (a-'a'+10) : 0
00113         );
00114     }
00115     inline char hex_byte(const char *str) const {
00116         return (hex_nib(*str) << 4) | hex_nib(*(str+1));
00117     }
00118     /**
00119      * To reduce memory usage we sodify the URL directly
00120      * and replace '%20',',','+','=' with spaces.
00121      */
00122 //    mutable char _buf[1024];
00123     inline char *clean(char *str) const {
00124       char *in = str;
00125 //      char *out = _buf;
00126       char *out = str;    // this will do conversions in-place.
00127       bool inquotes=false;
00128       bool backslash=false;
00129       bool hasquery=false;
00130       bool cantquery=false;
00131         // cantquery=true will indicate that the URI already has symbols 
00132         // incompatible with query, so it disables checking for query.
00133 #if HTTPRPC_USE_URI_FIELDS
00134       bool infield=false;
00135 //      bool rpcquery=false;
00136       char *field=out;
00137 #endif
00138 
00139 printf("\r\nDEBUG HTTPRPC::clean() IN=:%s:\r\n",str);
00140       while (*in) {
00141 #if HTTPRPC_USE_URI_FIELDS
00142         // Check if URI has query part
00143         // in form "/rpc/obj/method?arg1=val1&arg2=val2&arg3=val3"
00144         if (!inquotes && !cantquery && !hasquery && *in == '?') {
00145           hasquery = true;
00146           *out = ' '; out++;  // delimit base URI part
00147           infield = true; in++; field=in; continue;
00148           // New field started. Do nothing yet
00149         }
00150         // Check if URI with query part is delimited
00151         if (!inquotes && !infield && hasquery && *in == '&') {
00152           *out = ' '; out++;  // delimit current arg
00153           infield = true; in++; field=in; continue;
00154           // New field started
00155         }
00156         if (infield) {
00157           // Process the query - skip till '='
00158           // Also check if it is in form "/rpc/obj/method?val1&val2&val3"
00159           if (!inquotes && *in == '&') {
00160             // modified query - catch up
00161             while (field<in) {
00162               *out = *field;
00163               if (*field=='%' && is_hex(*(field+1)) && is_hex(*(field+2)) ) {
00164                 *out = hex_byte(++field);
00165                 field++;    // field is incremented by 2 total
00166               }
00167               if (!backslash && *out == '"') { inquotes = !inquotes; }
00168               backslash = inquotes && !backslash && (*out == '\\');
00169 
00170               out++;
00171               field++;
00172             }
00173             
00174             *out = ' '; out++;  // delimit current arg
00175             infield = true; in++; field=in; continue;
00176             // New field started
00177           } else
00178           if (!inquotes && *in == '=') {
00179             infield = false;
00180             *in = '\0';  // this will mark the field name
00181 printf("    - field: %s\r\n", field);
00182 // FIXME: here we have a field/arg name. Can we use it to reorder the arguments for the rpc?
00183 
00184           } else {
00185             // Keep tracking quotes
00186             char tmp = *in;
00187             if (*in=='%' && is_hex(*(in+1)) && is_hex(*(in+2)) ) {
00188               tmp = hex_byte(++in);
00189               in++;    // in is incremented by 2 total
00190             }
00191             if (!backslash && tmp == '"') { inquotes = !inquotes; }
00192             backslash = inquotes && !backslash && (tmp == '\\');
00193           }
00194         } else
00195 #endif    // HTTPRPC_USE_URI_FIELDS
00196         {
00197           // Keep processing the stream
00198           *out = *in;
00199 
00200           if (*in=='%' && is_hex(*(in+1)) && is_hex(*(in+2)) ) {
00201             *out = hex_byte(++in);
00202             in++;    // in is incremented by 2 total
00203             cantquery = !hasquery;   // any %-encoded before '?' means it can't be a query
00204           } else
00205           if (!inquotes && !hasquery && (*in==',' || *in=='+' || *in=='=')) {
00206             *out = ' ';
00207 //            cantquery = !hasquery;   // any non-query delimiter disallows URI query
00208           }
00209           if (!backslash && *out == '"') { inquotes = !inquotes; }
00210           backslash = inquotes && !backslash && (*out == '\\');
00211 
00212           out++;
00213         }
00214 
00215         in++;
00216       } // while
00217 
00218 #if HTTPRPC_USE_URI_FIELDS
00219       if (infield) {
00220         // modified query last arg - catch up
00221         while (field < in) {
00222           *out = *field;
00223           if (*field=='%' && is_hex(*(field+1)) && is_hex(*(field+2)) ) {
00224             *out = hex_byte(++field);
00225             field++;    // field is incremented by 2 total
00226           }
00227           if (!backslash && *out == '"') { inquotes = !inquotes; }
00228           backslash = inquotes && !backslash && (*out == '\\');
00229 
00230           out++;
00231           field++;
00232         }
00233       }
00234 #endif    // HTTPRPC_USE_URI_FIELDS
00235 
00236       hasquery = cantquery; // only removes compiler warning
00237       *out = '\0';
00238 
00239 //      out = _buf;
00240       out = str;
00241 printf("DEBUG HTTPRPC::clean() OUT=:%s:\r\n", out);
00242       return out;
00243     }
00244 };
00245 #endif
00246 
00247 #endif