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.
lwip/HTTPServer/HTTPRPC.h
- Committer:
- geiineuville
- Date:
- 2011-09-22
- Revision:
- 0:3c32eeb9292a
File content as of revision 0:3c32eeb9292a:
// HTTPRPC.h
// Modified by iva2k
// Improved URL string handling
//
#ifndef HTTPRPC_H
#define HTTPRPC_H
#include "HTTPServer.h"
#include "platform.h"
#ifdef MBED_RPC
#include "rpc.h"
#ifndef HTTPRPC_USE_URI_FIELDS
#define HTTPRPC_USE_URI_FIELDS 1
#endif
/**
* A datastorage helper for the HTTPRPC class
*/
class HTTPRPCData : public HTTPData {
public: char result[255];
};
/**
* Thsi class enables you to make rpc calls to your mbed.
* Furthermore it is a good example how to write a HTTPHandler for small data chunks.
*/
class HTTPRPC : public HTTPHandler {
public:
/**
* We have to know the prefix for the RPCHandler.
* A good default choice is /rpc so we made this default.
*/
HTTPRPC(const char *path = "/rpc") : HTTPHandler(path) {}
HTTPRPC(HTTPServer *server, const char *path = "/rpc") : HTTPHandler(path) { server->addHandler(this); }
private:
/**
* If you need some Headerfeelds you have tor register the feelds here.
*/
// virtual void reg(HTTPServer *svr) {
// svr->registerField("Content-Length");
// }
/**
* If a new RPCRequest Header is complete received the server will call this function.
* This is the right place for preparing our datastructures.
* Furthermore we will execute the rpc call and store the anwere.
* But we will not send a response. This will be hapen in the send method.
*/
virtual HTTPStatus init(HTTPConnection *con) const {
HTTPRPCData *data = new HTTPRPCData();
con->data = data;
char *query = con->getURL()+strlen(_prefix);
query = clean(query);
rpc(query, data->result);
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";
char *old = (char *)con->getHeaderFields();
int oldlen = strlen(old);
int atrlen = strlen(nfields);
char *fields = new char[atrlen+oldlen+3];
strcpy(fields,old);
fields[oldlen+0] = '\r';
fields[oldlen+1] = '\n';
strcpy(&fields[oldlen+2], nfields);
fields[atrlen+2+oldlen] = '\0';
con->setHeaderFields(fields);
if(*old) {
delete old;
}
con->setLength(strlen(data->result));
return HTTP_OK;
}
/**
* If we got an POST request the send method will not be executed.
* If we want to send data we have to trigger it the first time by ourself.
* So we execute the send method.
*
* If the rpc call is the content of the POST body we would not be able to execute it.
* Were parsing only the URL.
*/
virtual HTTPHandle data(HTTPConnection *con, void *, int) const {
return send(con, con->sndbuf());
}
/**
* Send the result back to the client.
* If we have not enought space wait for next time.
*/
virtual HTTPHandle send(HTTPConnection *con, int maximum) const {
HTTPRPCData *data = static_cast<HTTPRPCData *>(con->data);
if(maximum>64) {
con->write(data->result, con->getLength());
return HTTP_SuccessEnded;
} else {
// To less memory.
return HTTP_SenderMemory;
}
}
inline bool is_hex(const char a) const {
return (a>='0' && a<='9') || (a>='A' && a<='F') || (a>='a' && a<='f');
}
inline char hex_nib(const char a) const {
return 0xf & (
(a>='0' && a<='9') ? (a-'0' ) :
(a>='A' && a<='F') ? (a-'A'+10) :
(a>='a' && a<='f') ? (a-'a'+10) : 0
);
}
inline char hex_byte(const char *str) const {
return (hex_nib(*str) << 4) | hex_nib(*(str+1));
}
/**
* To reduce memory usage we sodify the URL directly
* and replace '%20',',','+','=' with spaces.
*/
// mutable char _buf[1024];
inline char *clean(char *str) const {
char *in = str;
// char *out = _buf;
char *out = str; // this will do conversions in-place.
bool inquotes=false;
bool backslash=false;
bool hasquery=false;
bool cantquery=false;
// cantquery=true will indicate that the URI already has symbols
// incompatible with query, so it disables checking for query.
#if HTTPRPC_USE_URI_FIELDS
bool infield=false;
// bool rpcquery=false;
char *field=out;
#endif
printf("\r\nDEBUG HTTPRPC::clean() IN=:%s:\r\n",str);
while (*in) {
#if HTTPRPC_USE_URI_FIELDS
// Check if URI has query part
// in form "/rpc/obj/method?arg1=val1&arg2=val2&arg3=val3"
if (!inquotes && !cantquery && !hasquery && *in == '?') {
hasquery = true;
*out = ' '; out++; // delimit base URI part
infield = true; in++; field=in; continue;
// New field started. Do nothing yet
}
// Check if URI with query part is delimited
if (!inquotes && !infield && hasquery && *in == '&') {
*out = ' '; out++; // delimit current arg
infield = true; in++; field=in; continue;
// New field started
}
if (infield) {
// Process the query - skip till '='
// Also check if it is in form "/rpc/obj/method?val1&val2&val3"
if (!inquotes && *in == '&') {
// modified query - catch up
while (field<in) {
*out = *field;
if (*field=='%' && is_hex(*(field+1)) && is_hex(*(field+2)) ) {
*out = hex_byte(++field);
field++; // field is incremented by 2 total
}
if (!backslash && *out == '"') { inquotes = !inquotes; }
backslash = inquotes && !backslash && (*out == '\\');
out++;
field++;
}
*out = ' '; out++; // delimit current arg
infield = true; in++; field=in; continue;
// New field started
} else
if (!inquotes && *in == '=') {
infield = false;
*in = '\0'; // this will mark the field name
printf(" - field: %s\r\n", field);
// FIXME: here we have a field/arg name. Can we use it to reorder the arguments for the rpc?
} else {
// Keep tracking quotes
char tmp = *in;
if (*in=='%' && is_hex(*(in+1)) && is_hex(*(in+2)) ) {
tmp = hex_byte(++in);
in++; // in is incremented by 2 total
}
if (!backslash && tmp == '"') { inquotes = !inquotes; }
backslash = inquotes && !backslash && (tmp == '\\');
}
} else
#endif // HTTPRPC_USE_URI_FIELDS
{
// Keep processing the stream
*out = *in;
if (*in=='%' && is_hex(*(in+1)) && is_hex(*(in+2)) ) {
*out = hex_byte(++in);
in++; // in is incremented by 2 total
cantquery = !hasquery; // any %-encoded before '?' means it can't be a query
} else
if (!inquotes && !hasquery && (*in==',' || *in=='+' || *in=='=')) {
*out = ' ';
// cantquery = !hasquery; // any non-query delimiter disallows URI query
}
if (!backslash && *out == '"') { inquotes = !inquotes; }
backslash = inquotes && !backslash && (*out == '\\');
out++;
}
in++;
} // while
#if HTTPRPC_USE_URI_FIELDS
if (infield) {
// modified query last arg - catch up
while (field < in) {
*out = *field;
if (*field=='%' && is_hex(*(field+1)) && is_hex(*(field+2)) ) {
*out = hex_byte(++field);
field++; // field is incremented by 2 total
}
if (!backslash && *out == '"') { inquotes = !inquotes; }
backslash = inquotes && !backslash && (*out == '\\');
out++;
field++;
}
}
#endif // HTTPRPC_USE_URI_FIELDS
hasquery = cantquery; // only removes compiler warning
*out = '\0';
// out = _buf;
out = str;
printf("DEBUG HTTPRPC::clean() OUT=:%s:\r\n", out);
return out;
}
};
#endif
#endif