Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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
Generated on Tue Jul 12 2022 20:39:37 by
1.7.2