1
0
Fork 0

Initial commit for mongoose httpd

This commit is contained in:
Torsten Dreyer 2014-03-03 21:59:16 +01:00
parent 2beb0f29af
commit 63e9cbed40
35 changed files with 6963 additions and 481 deletions

View file

@ -6,3 +6,6 @@ endif()
if (ENABLE_IAX)
add_subdirectory(iaxclient/lib)
endif()
add_subdirectory(mongoose)
add_subdirectory(cjson)

11
3rdparty/cjson/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,11 @@
include(FlightGearComponent)
set(SOURCES
cJSON.c
)
set(HEADERS
cJSON.h
)
flightgear_component(CJSON "${SOURCES}" "${HEADERS}")

20
3rdparty/cjson/LICENSE vendored Normal file
View file

@ -0,0 +1,20 @@
Copyright (c) 2009 Dave Gamble
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

247
3rdparty/cjson/README vendored Normal file
View file

@ -0,0 +1,247 @@
/*
Copyright (c) 2009 Dave Gamble
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
Welcome to cJSON.
cJSON aims to be the dumbest possible parser that you can get your job done with.
It's a single file of C, and a single header file.
JSON is described best here: http://www.json.org/
It's like XML, but fat-free. You use it to move data around, store things, or just
generally represent your program's state.
First up, how do I build?
Add cJSON.c to your project, and put cJSON.h somewhere in the header search path.
For example, to build the test app:
gcc cJSON.c test.c -o test -lm
./test
As a library, cJSON exists to take away as much legwork as it can, but not get in your way.
As a point of pragmatism (i.e. ignoring the truth), I'm going to say that you can use it
in one of two modes: Auto and Manual. Let's have a quick run-through.
I lifted some JSON from this page: http://www.json.org/fatfree.html
That page inspired me to write cJSON, which is a parser that tries to share the same
philosophy as JSON itself. Simple, dumb, out of the way.
Some JSON:
{
"name": "Jack (\"Bee\") Nimble",
"format": {
"type": "rect",
"width": 1920,
"height": 1080,
"interlace": false,
"frame rate": 24
}
}
Assume that you got this from a file, a webserver, or magic JSON elves, whatever,
you have a char * to it. Everything is a cJSON struct.
Get it parsed:
cJSON *root = cJSON_Parse(my_json_string);
This is an object. We're in C. We don't have objects. But we do have structs.
What's the framerate?
cJSON *format = cJSON_GetObjectItem(root,"format");
int framerate = cJSON_GetObjectItem(format,"frame rate")->valueint;
Want to change the framerate?
cJSON_GetObjectItem(format,"frame rate")->valueint=25;
Back to disk?
char *rendered=cJSON_Print(root);
Finished? Delete the root (this takes care of everything else).
cJSON_Delete(root);
That's AUTO mode. If you're going to use Auto mode, you really ought to check pointers
before you dereference them. If you want to see how you'd build this struct in code?
cJSON *root,*fmt;
root=cJSON_CreateObject();
cJSON_AddItemToObject(root, "name", cJSON_CreateString("Jack (\"Bee\") Nimble"));
cJSON_AddItemToObject(root, "format", fmt=cJSON_CreateObject());
cJSON_AddStringToObject(fmt,"type", "rect");
cJSON_AddNumberToObject(fmt,"width", 1920);
cJSON_AddNumberToObject(fmt,"height", 1080);
cJSON_AddFalseToObject (fmt,"interlace");
cJSON_AddNumberToObject(fmt,"frame rate", 24);
Hopefully we can agree that's not a lot of code? There's no overhead, no unnecessary setup.
Look at test.c for a bunch of nice examples, mostly all ripped off the json.org site, and
a few from elsewhere.
What about manual mode? First up you need some detail.
Let's cover how the cJSON objects represent the JSON data.
cJSON doesn't distinguish arrays from objects in handling; just type.
Each cJSON has, potentially, a child, siblings, value, a name.
The root object has: Object Type and a Child
The Child has name "name", with value "Jack ("Bee") Nimble", and a sibling:
Sibling has type Object, name "format", and a child.
That child has type String, name "type", value "rect", and a sibling:
Sibling has type Number, name "width", value 1920, and a sibling:
Sibling has type Number, name "height", value 1080, and a sibling:
Sibling hs type False, name "interlace", and a sibling:
Sibling has type Number, name "frame rate", value 24
Here's the structure:
typedef struct cJSON {
struct cJSON *next,*prev;
struct cJSON *child;
int type;
char *valuestring;
int valueint;
double valuedouble;
char *string;
} cJSON;
By default all values are 0 unless set by virtue of being meaningful.
next/prev is a doubly linked list of siblings. next takes you to your sibling,
prev takes you back from your sibling to you.
Only objects and arrays have a "child", and it's the head of the doubly linked list.
A "child" entry will have prev==0, but next potentially points on. The last sibling has next=0.
The type expresses Null/True/False/Number/String/Array/Object, all of which are #defined in
cJSON.h
A Number has valueint and valuedouble. If you're expecting an int, read valueint, if not read
valuedouble.
Any entry which is in the linked list which is the child of an object will have a "string"
which is the "name" of the entry. When I said "name" in the above example, that's "string".
"string" is the JSON name for the 'variable name' if you will.
Now you can trivially walk the lists, recursively, and parse as you please.
You can invoke cJSON_Parse to get cJSON to parse for you, and then you can take
the root object, and traverse the structure (which is, formally, an N-tree),
and tokenise as you please. If you wanted to build a callback style parser, this is how
you'd do it (just an example, since these things are very specific):
void parse_and_callback(cJSON *item,const char *prefix)
{
while (item)
{
char *newprefix=malloc(strlen(prefix)+strlen(item->name)+2);
sprintf(newprefix,"%s/%s",prefix,item->name);
int dorecurse=callback(newprefix, item->type, item);
if (item->child && dorecurse) parse_and_callback(item->child,newprefix);
item=item->next;
free(newprefix);
}
}
The prefix process will build you a separated list, to simplify your callback handling.
The 'dorecurse' flag would let the callback decide to handle sub-arrays on it's own, or
let you invoke it per-item. For the item above, your callback might look like this:
int callback(const char *name,int type,cJSON *item)
{
if (!strcmp(name,"name")) { /* populate name */ }
else if (!strcmp(name,"format/type") { /* handle "rect" */ }
else if (!strcmp(name,"format/width") { /* 800 */ }
else if (!strcmp(name,"format/height") { /* 600 */ }
else if (!strcmp(name,"format/interlace") { /* false */ }
else if (!strcmp(name,"format/frame rate") { /* 24 */ }
return 1;
}
Alternatively, you might like to parse iteratively.
You'd use:
void parse_object(cJSON *item)
{
int i; for (i=0;i<cJSON_GetArraySize(item);i++)
{
cJSON *subitem=cJSON_GetArrayItem(item,i);
// handle subitem.
}
}
Or, for PROPER manual mode:
void parse_object(cJSON *item)
{
cJSON *subitem=item->child;
while (subitem)
{
// handle subitem
if (subitem->child) parse_object(subitem->child);
subitem=subitem->next;
}
}
Of course, this should look familiar, since this is just a stripped-down version
of the callback-parser.
This should cover most uses you'll find for parsing. The rest should be possible
to infer.. and if in doubt, read the source! There's not a lot of it! ;)
In terms of constructing JSON data, the example code above is the right way to do it.
You can, of course, hand your sub-objects to other functions to populate.
Also, if you find a use for it, you can manually build the objects.
For instance, suppose you wanted to build an array of objects?
cJSON *objects[24];
cJSON *Create_array_of_anything(cJSON **items,int num)
{
int i;cJSON *prev, *root=cJSON_CreateArray();
for (i=0;i<24;i++)
{
if (!i) root->child=objects[i];
else prev->next=objects[i], objects[i]->prev=prev;
prev=objects[i];
}
return root;
}
and simply: Create_array_of_anything(objects,24);
cJSON doesn't make any assumptions about what order you create things in.
You can attach the objects, as above, and later add children to each
of those objects.
As soon as you call cJSON_Print, it renders the structure to text.
The test.c code shows how to handle a bunch of typical cases. If you uncomment
the code, it'll load, parse and print a bunch of test files, also from json.org,
which are more complex than I'd care to try and stash into a const char array[].
Enjoy cJSON!
- Dave Gamble, Aug 2009

596
3rdparty/cjson/cJSON.c vendored Normal file
View file

@ -0,0 +1,596 @@
/*
Copyright (c) 2009 Dave Gamble
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/* cJSON */
/* JSON parser in C. */
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <float.h>
#include <limits.h>
#include <ctype.h>
#include "cJSON.h"
static const char *ep;
const char *cJSON_GetErrorPtr(void) {return ep;}
static int cJSON_strcasecmp(const char *s1,const char *s2)
{
if (!s1) return (s1==s2)?0:1;if (!s2) return 1;
for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0;
return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
}
static void *(*cJSON_malloc)(size_t sz) = malloc;
static void (*cJSON_free)(void *ptr) = free;
static char* cJSON_strdup(const char* str)
{
size_t len;
char* copy;
len = strlen(str) + 1;
if (!(copy = (char*)cJSON_malloc(len))) return 0;
memcpy(copy,str,len);
return copy;
}
void cJSON_InitHooks(cJSON_Hooks* hooks)
{
if (!hooks) { /* Reset hooks */
cJSON_malloc = malloc;
cJSON_free = free;
return;
}
cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
cJSON_free = (hooks->free_fn)?hooks->free_fn:free;
}
/* Internal constructor. */
static cJSON *cJSON_New_Item(void)
{
cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
if (node) memset(node,0,sizeof(cJSON));
return node;
}
/* Delete a cJSON structure. */
void cJSON_Delete(cJSON *c)
{
cJSON *next;
while (c)
{
next=c->next;
if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child);
if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring);
if (c->string) cJSON_free(c->string);
cJSON_free(c);
c=next;
}
}
/* Parse the input text to generate a number, and populate the result into item. */
static const char *parse_number(cJSON *item,const char *num)
{
double n=0,sign=1,scale=0;int subscale=0,signsubscale=1;
if (*num=='-') sign=-1,num++; /* Has sign? */
if (*num=='0') num++; /* is zero */
if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */
if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */
if (*num=='e' || *num=='E') /* Exponent? */
{ num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */
while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */
}
n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */
item->valuedouble=n;
item->valueint=(int)n;
item->type=cJSON_Number;
return num;
}
/* Render the number nicely from the given item into a string. */
static char *print_number(cJSON *item)
{
char *str;
double d=item->valuedouble;
if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
{
str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */
if (str) sprintf(str,"%d",item->valueint);
}
else
{
str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */
if (str)
{
if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d);
else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d);
else sprintf(str,"%f",d);
}
}
return str;
}
static unsigned parse_hex4(const char *str)
{
unsigned h=0;
if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
h=h<<4;str++;
if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
h=h<<4;str++;
if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
h=h<<4;str++;
if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
return h;
}
/* Parse the input text into an unescaped cstring, and populate item. */
static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
static const char *parse_string(cJSON *item,const char *str)
{
const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2;
if (*str!='\"') {ep=str;return 0;} /* not a string! */
while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */
out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */
if (!out) return 0;
ptr=str+1;ptr2=out;
while (*ptr!='\"' && *ptr)
{
if (*ptr!='\\') *ptr2++=*ptr++;
else
{
ptr++;
switch (*ptr)
{
case 'b': *ptr2++='\b'; break;
case 'f': *ptr2++='\f'; break;
case 'n': *ptr2++='\n'; break;
case 'r': *ptr2++='\r'; break;
case 't': *ptr2++='\t'; break;
case 'u': /* transcode utf16 to utf8. */
uc=parse_hex4(ptr+1);ptr+=4; /* get the unicode char. */
if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; /* check for invalid. */
if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */
{
if (ptr[1]!='\\' || ptr[2]!='u') break; /* missing second-half of surrogate. */
uc2=parse_hex4(ptr+3);ptr+=6;
if (uc2<0xDC00 || uc2>0xDFFF) break; /* invalid second-half of surrogate. */
uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF));
}
len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len;
switch (len) {
case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
case 1: *--ptr2 =(uc | firstByteMark[len]);
}
ptr2+=len;
break;
default: *ptr2++=*ptr; break;
}
ptr++;
}
}
*ptr2=0;
if (*ptr=='\"') ptr++;
item->valuestring=out;
item->type=cJSON_String;
return ptr;
}
/* Render the cstring provided to an escaped version that can be printed. */
static char *print_string_ptr(const char *str)
{
const char *ptr;char *ptr2,*out;int len=0;unsigned char token;
if (!str) return cJSON_strdup("");
ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;}
out=(char*)cJSON_malloc(len+3);
if (!out) return 0;
ptr2=out;ptr=str;
*ptr2++='\"';
while (*ptr)
{
if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;
else
{
*ptr2++='\\';
switch (token=*ptr++)
{
case '\\': *ptr2++='\\'; break;
case '\"': *ptr2++='\"'; break;
case '\b': *ptr2++='b'; break;
case '\f': *ptr2++='f'; break;
case '\n': *ptr2++='n'; break;
case '\r': *ptr2++='r'; break;
case '\t': *ptr2++='t'; break;
default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */
}
}
}
*ptr2++='\"';*ptr2++=0;
return out;
}
/* Invote print_string_ptr (which is useful) on an item. */
static char *print_string(cJSON *item) {return print_string_ptr(item->valuestring);}
/* Predeclare these prototypes. */
static const char *parse_value(cJSON *item,const char *value);
static char *print_value(cJSON *item,int depth,int fmt);
static const char *parse_array(cJSON *item,const char *value);
static char *print_array(cJSON *item,int depth,int fmt);
static const char *parse_object(cJSON *item,const char *value);
static char *print_object(cJSON *item,int depth,int fmt);
/* Utility to jump whitespace and cr/lf */
static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;}
/* Parse an object - create a new root, and populate. */
cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated)
{
const char *end=0;
cJSON *c=cJSON_New_Item();
ep=0;
if (!c) return 0; /* memory fail */
end=parse_value(c,skip(value));
if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */
/* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}}
if (return_parse_end) *return_parse_end=end;
return c;
}
/* Default options for cJSON_Parse */
cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);}
/* Render a cJSON item/entity/structure to text. */
char *cJSON_Print(cJSON *item) {return print_value(item,0,1);}
char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0);}
/* Parser core - when encountering text, process appropriately. */
static const char *parse_value(cJSON *item,const char *value)
{
if (!value) return 0; /* Fail on null. */
if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; }
if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; }
if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; }
if (*value=='\"') { return parse_string(item,value); }
if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); }
if (*value=='[') { return parse_array(item,value); }
if (*value=='{') { return parse_object(item,value); }
ep=value;return 0; /* failure. */
}
/* Render a value to text. */
static char *print_value(cJSON *item,int depth,int fmt)
{
char *out=0;
if (!item) return 0;
switch ((item->type)&255)
{
case cJSON_NULL: out=cJSON_strdup("null"); break;
case cJSON_False: out=cJSON_strdup("false");break;
case cJSON_True: out=cJSON_strdup("true"); break;
case cJSON_Number: out=print_number(item);break;
case cJSON_String: out=print_string(item);break;
case cJSON_Array: out=print_array(item,depth,fmt);break;
case cJSON_Object: out=print_object(item,depth,fmt);break;
}
return out;
}
/* Build an array from input text. */
static const char *parse_array(cJSON *item,const char *value)
{
cJSON *child;
if (*value!='[') {ep=value;return 0;} /* not an array! */
item->type=cJSON_Array;
value=skip(value+1);
if (*value==']') return value+1; /* empty array. */
item->child=child=cJSON_New_Item();
if (!item->child) return 0; /* memory fail */
value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */
if (!value) return 0;
while (*value==',')
{
cJSON *new_item;
if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */
child->next=new_item;new_item->prev=child;child=new_item;
value=skip(parse_value(child,skip(value+1)));
if (!value) return 0; /* memory fail */
}
if (*value==']') return value+1; /* end of array */
ep=value;return 0; /* malformed. */
}
/* Render an array to text */
static char *print_array(cJSON *item,int depth,int fmt)
{
char **entries;
char *out=0,*ptr,*ret;int len=5;
cJSON *child=item->child;
int numentries=0,i=0,fail=0;
/* How many entries in the array? */
while (child) numentries++,child=child->next;
/* Explicitly handle numentries==0 */
if (!numentries)
{
out=(char*)cJSON_malloc(3);
if (out) strcpy(out,"[]");
return out;
}
/* Allocate an array to hold the values for each */
entries=(char**)cJSON_malloc(numentries*sizeof(char*));
if (!entries) return 0;
memset(entries,0,numentries*sizeof(char*));
/* Retrieve all the results: */
child=item->child;
while (child && !fail)
{
ret=print_value(child,depth+1,fmt);
entries[i++]=ret;
if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1;
child=child->next;
}
/* If we didn't fail, try to malloc the output string */
if (!fail) out=(char*)cJSON_malloc(len);
/* If that fails, we fail. */
if (!out) fail=1;
/* Handle failure. */
if (fail)
{
for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]);
cJSON_free(entries);
return 0;
}
/* Compose the output array. */
*out='[';
ptr=out+1;*ptr=0;
for (i=0;i<numentries;i++)
{
strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;}
cJSON_free(entries[i]);
}
cJSON_free(entries);
*ptr++=']';*ptr++=0;
return out;
}
/* Build an object from the text. */
static const char *parse_object(cJSON *item,const char *value)
{
cJSON *child;
if (*value!='{') {ep=value;return 0;} /* not an object! */
item->type=cJSON_Object;
value=skip(value+1);
if (*value=='}') return value+1; /* empty array. */
item->child=child=cJSON_New_Item();
if (!item->child) return 0;
value=skip(parse_string(child,skip(value)));
if (!value) return 0;
child->string=child->valuestring;child->valuestring=0;
if (*value!=':') {ep=value;return 0;} /* fail! */
value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
if (!value) return 0;
while (*value==',')
{
cJSON *new_item;
if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */
child->next=new_item;new_item->prev=child;child=new_item;
value=skip(parse_string(child,skip(value+1)));
if (!value) return 0;
child->string=child->valuestring;child->valuestring=0;
if (*value!=':') {ep=value;return 0;} /* fail! */
value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
if (!value) return 0;
}
if (*value=='}') return value+1; /* end of array */
ep=value;return 0; /* malformed. */
}
/* Render an object to text. */
static char *print_object(cJSON *item,int depth,int fmt)
{
char **entries=0,**names=0;
char *out=0,*ptr,*ret,*str;int len=7,i=0,j;
cJSON *child=item->child;
int numentries=0,fail=0;
/* Count the number of entries. */
while (child) numentries++,child=child->next;
/* Explicitly handle empty object case */
if (!numentries)
{
out=(char*)cJSON_malloc(fmt?depth+4:3);
if (!out) return 0;
ptr=out;*ptr++='{';
if (fmt) {*ptr++='\n';for (i=0;i<depth-1;i++) *ptr++='\t';}
*ptr++='}';*ptr++=0;
return out;
}
/* Allocate space for the names and the objects */
entries=(char**)cJSON_malloc(numentries*sizeof(char*));
if (!entries) return 0;
names=(char**)cJSON_malloc(numentries*sizeof(char*));
if (!names) {cJSON_free(entries);return 0;}
memset(entries,0,sizeof(char*)*numentries);
memset(names,0,sizeof(char*)*numentries);
/* Collect all the results into our arrays: */
child=item->child;depth++;if (fmt) len+=depth;
while (child)
{
names[i]=str=print_string_ptr(child->string);
entries[i++]=ret=print_value(child,depth,fmt);
if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1;
child=child->next;
}
/* Try to allocate the output string */
if (!fail) out=(char*)cJSON_malloc(len);
if (!out) fail=1;
/* Handle failure */
if (fail)
{
for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);}
cJSON_free(names);cJSON_free(entries);
return 0;
}
/* Compose the output: */
*out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0;
for (i=0;i<numentries;i++)
{
if (fmt) for (j=0;j<depth;j++) *ptr++='\t';
strcpy(ptr,names[i]);ptr+=strlen(names[i]);
*ptr++=':';if (fmt) *ptr++='\t';
strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
if (i!=numentries-1) *ptr++=',';
if (fmt) *ptr++='\n';*ptr=0;
cJSON_free(names[i]);cJSON_free(entries[i]);
}
cJSON_free(names);cJSON_free(entries);
if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t';
*ptr++='}';*ptr++=0;
return out;
}
/* Get Array size/item / object item. */
int cJSON_GetArraySize(cJSON *array) {cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;}
cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;}
cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;}
/* Utility for array list handling. */
static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
/* Utility for handling references. */
static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;}
/* Add item to array/object. */
void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}}
void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);}
void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));}
void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));}
cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0;
if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;}
void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));}
cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;}
void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));}
/* Replace array/object items with new ones. */
void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return;
newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem;
if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);}
void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}}
/* Create basic types: */
cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;}
cJSON *cJSON_CreateTrue(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;}
cJSON *cJSON_CreateFalse(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;}
cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;}
cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;}
cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;}
cJSON *cJSON_CreateArray(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;}
cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;}
/* Create Arrays: */
cJSON *cJSON_CreateIntArray(const int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
cJSON *cJSON_CreateFloatArray(const float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
cJSON *cJSON_CreateDoubleArray(const double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateString(strings[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
/* Duplication */
cJSON *cJSON_Duplicate(cJSON *item,int recurse)
{
cJSON *newitem,*cptr,*nptr=0,*newchild;
/* Bail on bad ptr */
if (!item) return 0;
/* Create new item */
newitem=cJSON_New_Item();
if (!newitem) return 0;
/* Copy over all vars */
newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble;
if (item->valuestring) {newitem->valuestring=cJSON_strdup(item->valuestring); if (!newitem->valuestring) {cJSON_Delete(newitem);return 0;}}
if (item->string) {newitem->string=cJSON_strdup(item->string); if (!newitem->string) {cJSON_Delete(newitem);return 0;}}
/* If non-recursive, then we're done! */
if (!recurse) return newitem;
/* Walk the ->next chain for the child. */
cptr=item->child;
while (cptr)
{
newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */
if (!newchild) {cJSON_Delete(newitem);return 0;}
if (nptr) {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* If newitem->child already set, then crosswire ->prev and ->next and move on */
else {newitem->child=newchild;nptr=newchild;} /* Set newitem->child and move to it */
cptr=cptr->next;
}
return newitem;
}
void cJSON_Minify(char *json)
{
char *into=json;
while (*json)
{
if (*json==' ') json++;
else if (*json=='\t') json++; // Whitespace characters.
else if (*json=='\r') json++;
else if (*json=='\n') json++;
else if (*json=='/' && json[1]=='/') while (*json && *json!='\n') json++; // double-slash comments, to end of line.
else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;} // multiline comments.
else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} // string literals, which are \" sensitive.
else *into++=*json++; // All other characters.
}
*into=0; // and null-terminate.
}

143
3rdparty/cjson/cJSON.h vendored Normal file
View file

@ -0,0 +1,143 @@
/*
Copyright (c) 2009 Dave Gamble
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef cJSON__h
#define cJSON__h
#ifdef __cplusplus
extern "C"
{
#endif
/* cJSON Types: */
#define cJSON_False 0
#define cJSON_True 1
#define cJSON_NULL 2
#define cJSON_Number 3
#define cJSON_String 4
#define cJSON_Array 5
#define cJSON_Object 6
#define cJSON_IsReference 256
/* The cJSON structure: */
typedef struct cJSON {
struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
int type; /* The type of the item, as above. */
char *valuestring; /* The item's string, if type==cJSON_String */
int valueint; /* The item's number, if type==cJSON_Number */
double valuedouble; /* The item's number, if type==cJSON_Number */
char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
} cJSON;
typedef struct cJSON_Hooks {
void *(*malloc_fn)(size_t sz);
void (*free_fn)(void *ptr);
} cJSON_Hooks;
/* Supply malloc, realloc and free functions to cJSON */
extern void cJSON_InitHooks(cJSON_Hooks* hooks);
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
extern cJSON *cJSON_Parse(const char *value);
/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
extern char *cJSON_Print(cJSON *item);
/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
extern char *cJSON_PrintUnformatted(cJSON *item);
/* Delete a cJSON entity and all subentities. */
extern void cJSON_Delete(cJSON *c);
/* Returns the number of items in an array (or object). */
extern int cJSON_GetArraySize(cJSON *array);
/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
/* Get item "string" from object. Case insensitive. */
extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
extern const char *cJSON_GetErrorPtr(void);
/* These calls create a cJSON item of the appropriate type. */
extern cJSON *cJSON_CreateNull(void);
extern cJSON *cJSON_CreateTrue(void);
extern cJSON *cJSON_CreateFalse(void);
extern cJSON *cJSON_CreateBool(int b);
extern cJSON *cJSON_CreateNumber(double num);
extern cJSON *cJSON_CreateString(const char *string);
extern cJSON *cJSON_CreateArray(void);
extern cJSON *cJSON_CreateObject(void);
/* These utilities create an Array of count items. */
extern cJSON *cJSON_CreateIntArray(const int *numbers,int count);
extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count);
extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count);
extern cJSON *cJSON_CreateStringArray(const char **strings,int count);
/* Append item to the specified array/object. */
extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);
/* Remove/Detatch items from Arrays/Objects. */
extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which);
extern void cJSON_DeleteItemFromArray(cJSON *array,int which);
extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string);
extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string);
/* Update array items. */
extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);
extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
/* Duplicate a cJSON item */
extern cJSON *cJSON_Duplicate(cJSON *item,int recurse);
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
need to be released. With recurse!=0, it will duplicate any children connected to the item.
The item->next and ->prev pointers are always zero on return from Duplicate. */
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated);
extern void cJSON_Minify(char *json);
/* Macros for creating things quickly. */
#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
#define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val))
#ifdef __cplusplus
}
#endif
#endif

156
3rdparty/cjson/test.c vendored Normal file
View file

@ -0,0 +1,156 @@
/*
Copyright (c) 2009 Dave Gamble
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"
/* Parse text to JSON, then render back to text, and print! */
void doit(char *text)
{
char *out;cJSON *json;
json=cJSON_Parse(text);
if (!json) {printf("Error before: [%s]\n",cJSON_GetErrorPtr());}
else
{
out=cJSON_Print(json);
cJSON_Delete(json);
printf("%s\n",out);
free(out);
}
}
/* Read a file, parse, render back, etc. */
void dofile(char *filename)
{
FILE *f=fopen(filename,"rb");fseek(f,0,SEEK_END);long len=ftell(f);fseek(f,0,SEEK_SET);
char *data=(char*)malloc(len+1);fread(data,1,len,f);fclose(f);
doit(data);
free(data);
}
/* Used by some code below as an example datatype. */
struct record {const char *precision;double lat,lon;const char *address,*city,*state,*zip,*country; };
/* Create a bunch of objects as demonstration. */
void create_objects()
{
cJSON *root,*fmt,*img,*thm,*fld;char *out;int i; /* declare a few. */
/* Here we construct some JSON standards, from the JSON site. */
/* Our "Video" datatype: */
root=cJSON_CreateObject();
cJSON_AddItemToObject(root, "name", cJSON_CreateString("Jack (\"Bee\") Nimble"));
cJSON_AddItemToObject(root, "format", fmt=cJSON_CreateObject());
cJSON_AddStringToObject(fmt,"type", "rect");
cJSON_AddNumberToObject(fmt,"width", 1920);
cJSON_AddNumberToObject(fmt,"height", 1080);
cJSON_AddFalseToObject (fmt,"interlace");
cJSON_AddNumberToObject(fmt,"frame rate", 24);
out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out); /* Print to text, Delete the cJSON, print it, release the string. */
/* Our "days of the week" array: */
const char *strings[7]={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
root=cJSON_CreateStringArray(strings,7);
out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out);
/* Our matrix: */
int numbers[3][3]={{0,-1,0},{1,0,0},{0,0,1}};
root=cJSON_CreateArray();
for (i=0;i<3;i++) cJSON_AddItemToArray(root,cJSON_CreateIntArray(numbers[i],3));
/* cJSON_ReplaceItemInArray(root,1,cJSON_CreateString("Replacement")); */
out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out);
/* Our "gallery" item: */
int ids[4]={116,943,234,38793};
root=cJSON_CreateObject();
cJSON_AddItemToObject(root, "Image", img=cJSON_CreateObject());
cJSON_AddNumberToObject(img,"Width",800);
cJSON_AddNumberToObject(img,"Height",600);
cJSON_AddStringToObject(img,"Title","View from 15th Floor");
cJSON_AddItemToObject(img, "Thumbnail", thm=cJSON_CreateObject());
cJSON_AddStringToObject(thm, "Url", "http:/*www.example.com/image/481989943");
cJSON_AddNumberToObject(thm,"Height",125);
cJSON_AddStringToObject(thm,"Width","100");
cJSON_AddItemToObject(img,"IDs", cJSON_CreateIntArray(ids,4));
out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out);
/* Our array of "records": */
struct record fields[2]={
{"zip",37.7668,-1.223959e+2,"","SAN FRANCISCO","CA","94107","US"},
{"zip",37.371991,-1.22026e+2,"","SUNNYVALE","CA","94085","US"}};
root=cJSON_CreateArray();
for (i=0;i<2;i++)
{
cJSON_AddItemToArray(root,fld=cJSON_CreateObject());
cJSON_AddStringToObject(fld, "precision", fields[i].precision);
cJSON_AddNumberToObject(fld, "Latitude", fields[i].lat);
cJSON_AddNumberToObject(fld, "Longitude", fields[i].lon);
cJSON_AddStringToObject(fld, "Address", fields[i].address);
cJSON_AddStringToObject(fld, "City", fields[i].city);
cJSON_AddStringToObject(fld, "State", fields[i].state);
cJSON_AddStringToObject(fld, "Zip", fields[i].zip);
cJSON_AddStringToObject(fld, "Country", fields[i].country);
}
/* cJSON_ReplaceItemInObject(cJSON_GetArrayItem(root,1),"City",cJSON_CreateIntArray(ids,4)); */
out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out);
}
int main (int argc, const char * argv[]) {
/* a bunch of json: */
char text1[]="{\n\"name\": \"Jack (\\\"Bee\\\") Nimble\", \n\"format\": {\"type\": \"rect\", \n\"width\": 1920, \n\"height\": 1080, \n\"interlace\": false,\"frame rate\": 24\n}\n}";
char text2[]="[\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"]";
char text3[]="[\n [0, -1, 0],\n [1, 0, 0],\n [0, 0, 1]\n ]\n";
char text4[]="{\n \"Image\": {\n \"Width\": 800,\n \"Height\": 600,\n \"Title\": \"View from 15th Floor\",\n \"Thumbnail\": {\n \"Url\": \"http:/*www.example.com/image/481989943\",\n \"Height\": 125,\n \"Width\": \"100\"\n },\n \"IDs\": [116, 943, 234, 38793]\n }\n }";
char text5[]="[\n {\n \"precision\": \"zip\",\n \"Latitude\": 37.7668,\n \"Longitude\": -122.3959,\n \"Address\": \"\",\n \"City\": \"SAN FRANCISCO\",\n \"State\": \"CA\",\n \"Zip\": \"94107\",\n \"Country\": \"US\"\n },\n {\n \"precision\": \"zip\",\n \"Latitude\": 37.371991,\n \"Longitude\": -122.026020,\n \"Address\": \"\",\n \"City\": \"SUNNYVALE\",\n \"State\": \"CA\",\n \"Zip\": \"94085\",\n \"Country\": \"US\"\n }\n ]";
/* Process each json textblock by parsing, then rebuilding: */
doit(text1);
doit(text2);
doit(text3);
doit(text4);
doit(text5);
/* Parse standard testfiles: */
/* dofile("../../tests/test1"); */
/* dofile("../../tests/test2"); */
/* dofile("../../tests/test3"); */
/* dofile("../../tests/test4"); */
/* dofile("../../tests/test5"); */
/* Now some samplecode for building objects concisely: */
create_objects();
return 0;
}

22
3rdparty/cjson/tests/test1 vendored Normal file
View file

@ -0,0 +1,22 @@
{
"glossary": {
"title": "example glossary",
"GlossDiv": {
"title": "S",
"GlossList": {
"GlossEntry": {
"ID": "SGML",
"SortAs": "SGML",
"GlossTerm": "Standard Generalized Markup Language",
"Acronym": "SGML",
"Abbrev": "ISO 8879:1986",
"GlossDef": {
"para": "A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso": ["GML", "XML"]
},
"GlossSee": "markup"
}
}
}
}
}

11
3rdparty/cjson/tests/test2 vendored Normal file
View file

@ -0,0 +1,11 @@
{"menu": {
"id": "file",
"value": "File",
"popup": {
"menuitem": [
{"value": "New", "onclick": "CreateNewDoc()"},
{"value": "Open", "onclick": "OpenDoc()"},
{"value": "Close", "onclick": "CloseDoc()"}
]
}
}}

26
3rdparty/cjson/tests/test3 vendored Normal file
View file

@ -0,0 +1,26 @@
{"widget": {
"debug": "on",
"window": {
"title": "Sample Konfabulator Widget",
"name": "main_window",
"width": 500,
"height": 500
},
"image": {
"src": "Images/Sun.png",
"name": "sun1",
"hOffset": 250,
"vOffset": 250,
"alignment": "center"
},
"text": {
"data": "Click Here",
"size": 36,
"style": "bold",
"name": "text1",
"hOffset": 250,
"vOffset": 100,
"alignment": "center",
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
}
}}

88
3rdparty/cjson/tests/test4 vendored Normal file
View file

@ -0,0 +1,88 @@
{"web-app": {
"servlet": [
{
"servlet-name": "cofaxCDS",
"servlet-class": "org.cofax.cds.CDSServlet",
"init-param": {
"configGlossary:installationAt": "Philadelphia, PA",
"configGlossary:adminEmail": "ksm@pobox.com",
"configGlossary:poweredBy": "Cofax",
"configGlossary:poweredByIcon": "/images/cofax.gif",
"configGlossary:staticPath": "/content/static",
"templateProcessorClass": "org.cofax.WysiwygTemplate",
"templateLoaderClass": "org.cofax.FilesTemplateLoader",
"templatePath": "templates",
"templateOverridePath": "",
"defaultListTemplate": "listTemplate.htm",
"defaultFileTemplate": "articleTemplate.htm",
"useJSP": false,
"jspListTemplate": "listTemplate.jsp",
"jspFileTemplate": "articleTemplate.jsp",
"cachePackageTagsTrack": 200,
"cachePackageTagsStore": 200,
"cachePackageTagsRefresh": 60,
"cacheTemplatesTrack": 100,
"cacheTemplatesStore": 50,
"cacheTemplatesRefresh": 15,
"cachePagesTrack": 200,
"cachePagesStore": 100,
"cachePagesRefresh": 10,
"cachePagesDirtyRead": 10,
"searchEngineListTemplate": "forSearchEnginesList.htm",
"searchEngineFileTemplate": "forSearchEngines.htm",
"searchEngineRobotsDb": "WEB-INF/robots.db",
"useDataStore": true,
"dataStoreClass": "org.cofax.SqlDataStore",
"redirectionClass": "org.cofax.SqlRedirection",
"dataStoreName": "cofax",
"dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver",
"dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon",
"dataStoreUser": "sa",
"dataStorePassword": "dataStoreTestQuery",
"dataStoreTestQuery": "SET NOCOUNT ON;select test='test';",
"dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log",
"dataStoreInitConns": 10,
"dataStoreMaxConns": 100,
"dataStoreConnUsageLimit": 100,
"dataStoreLogLevel": "debug",
"maxUrlLength": 500}},
{
"servlet-name": "cofaxEmail",
"servlet-class": "org.cofax.cds.EmailServlet",
"init-param": {
"mailHost": "mail1",
"mailHostOverride": "mail2"}},
{
"servlet-name": "cofaxAdmin",
"servlet-class": "org.cofax.cds.AdminServlet"},
{
"servlet-name": "fileServlet",
"servlet-class": "org.cofax.cds.FileServlet"},
{
"servlet-name": "cofaxTools",
"servlet-class": "org.cofax.cms.CofaxToolsServlet",
"init-param": {
"templatePath": "toolstemplates/",
"log": 1,
"logLocation": "/usr/local/tomcat/logs/CofaxTools.log",
"logMaxSize": "",
"dataLog": 1,
"dataLogLocation": "/usr/local/tomcat/logs/dataLog.log",
"dataLogMaxSize": "",
"removePageCache": "/content/admin/remove?cache=pages&id=",
"removeTemplateCache": "/content/admin/remove?cache=templates&id=",
"fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder",
"lookInContext": 1,
"adminGroupID": 4,
"betaServer": true}}],
"servlet-mapping": {
"cofaxCDS": "/",
"cofaxEmail": "/cofaxutil/aemail/*",
"cofaxAdmin": "/admin/*",
"fileServlet": "/static/*",
"cofaxTools": "/tools/*"},
"taglib": {
"taglib-uri": "cofax.tld",
"taglib-location": "/WEB-INF/tlds/cofax.tld"}}}

27
3rdparty/cjson/tests/test5 vendored Normal file
View file

@ -0,0 +1,27 @@
{"menu": {
"header": "SVG Viewer",
"items": [
{"id": "Open"},
{"id": "OpenNew", "label": "Open New"},
null,
{"id": "ZoomIn", "label": "Zoom In"},
{"id": "ZoomOut", "label": "Zoom Out"},
{"id": "OriginalView", "label": "Original View"},
null,
{"id": "Quality"},
{"id": "Pause"},
{"id": "Mute"},
null,
{"id": "Find", "label": "Find..."},
{"id": "FindAgain", "label": "Find Again"},
{"id": "Copy"},
{"id": "CopyAgain", "label": "Copy Again"},
{"id": "CopySVG", "label": "Copy SVG"},
{"id": "ViewSVG", "label": "View SVG"},
{"id": "ViewSource", "label": "View Source"},
{"id": "SaveAs", "label": "Save As"},
null,
{"id": "Help"},
{"id": "About", "label": "About Adobe CVG Viewer..."}
]
}}

11
3rdparty/mongoose/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,11 @@
include(FlightGearComponent)
set(SOURCES
mongoose.c
)
set(HEADERS
mongoose.h
)
flightgear_component(Mongoose "${SOURCES}" "${HEADERS}")

16
3rdparty/mongoose/LICENSE vendored Normal file
View file

@ -0,0 +1,16 @@
Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
Copyright (c) 2013 Cesanta Software Limited
All rights reserved
This code is dual-licensed: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation. For the terms of this
license, see http://www.gnu.org/licenses.
You are free to use this code under the terms of the GNU General
Public License, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
Alternatively, you can license this code under a commercial
license, as set out in http://cesanta.com/products.html.

4211
3rdparty/mongoose/mongoose.c vendored Normal file

File diff suppressed because it is too large Load diff

123
3rdparty/mongoose/mongoose.h vendored Normal file
View file

@ -0,0 +1,123 @@
// Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
// Copyright (c) 2013-2014 Cesanta Software Limited
// All rights reserved
//
// This library is dual-licensed: you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation. For the terms of this
// license, see <http://www.gnu.org/licenses/>.
//
// You are free to use this library under the terms of the GNU General
// Public License, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// Alternatively, you can license this library under a commercial
// license, as set out in <http://cesanta.com/>.
//
// NOTE: Detailed API documentation is at http://cesanta.com/#docs
#ifndef MONGOOSE_HEADER_INCLUDED
#define MONGOOSE_HEADER_INCLUDED
#define MONGOOSE_VERSION "5.2"
#include <stdio.h> // required for FILE
#include <stddef.h> // required for size_t
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
// This structure contains information about HTTP request.
struct mg_connection {
const char *request_method; // "GET", "POST", etc
const char *uri; // URL-decoded URI
const char *http_version; // E.g. "1.0", "1.1"
const char *query_string; // URL part after '?', not including '?', or NULL
char remote_ip[48]; // Max IPv6 string length is 45 characters
const char *local_ip; // Local IP address
unsigned short remote_port; // Client's port
unsigned short local_port; // Local port number
int num_headers; // Number of HTTP headers
struct mg_header {
const char *name; // HTTP header name
const char *value; // HTTP header value
} http_headers[30];
char *content; // POST (or websocket message) data, or NULL
size_t content_len; // content length
int is_websocket; // Connection is a websocket connection
int status_code; // HTTP status code for HTTP error handler
int wsbits; // First byte of the websocket frame
void *server_param; // Parameter passed to mg_add_uri_handler()
void *connection_param; // Placeholder for connection-specific data
};
struct mg_server; // Opaque structure describing server instance
typedef int (*mg_handler_t)(struct mg_connection *);
// Server management functions
struct mg_server *mg_create_server(void *server_param);
void mg_destroy_server(struct mg_server **);
const char *mg_set_option(struct mg_server *, const char *opt, const char *val);
unsigned int mg_poll_server(struct mg_server *, int milliseconds);
void mg_set_request_handler(struct mg_server *, mg_handler_t);
void mg_set_http_error_handler(struct mg_server *, mg_handler_t);
void mg_set_auth_handler(struct mg_server *, mg_handler_t);
const char **mg_get_valid_option_names(void);
const char *mg_get_option(const struct mg_server *server, const char *name);
void mg_set_listening_socket(struct mg_server *, int sock);
int mg_get_listening_socket(struct mg_server *);
void mg_iterate_over_connections(struct mg_server *, mg_handler_t, void *);
// Connection management functions
void mg_send_status(struct mg_connection *, int status_code);
void mg_send_header(struct mg_connection *, const char *name, const char *val);
void mg_send_data(struct mg_connection *, const void *data, int data_len);
void mg_printf_data(struct mg_connection *, const char *format, ...);
int mg_websocket_write(struct mg_connection *, int opcode,
const char *data, size_t data_len);
// Deprecated in favor of mg_send_* interface
int mg_write(struct mg_connection *, const void *buf, int len);
int mg_printf(struct mg_connection *conn, const char *fmt, ...);
const char *mg_get_header(const struct mg_connection *, const char *name);
const char *mg_get_mime_type(const char *name, const char *default_mime_type);
int mg_get_var(const struct mg_connection *conn, const char *var_name,
char *buf, size_t buf_len);
int mg_parse_header(const char *hdr, const char *var_name, char *buf, size_t);
int mg_parse_multipart(const char *buf, int buf_len,
char *var_name, int var_name_len,
char *file_name, int file_name_len,
const char **data, int *data_len);
// Utility functions
void *mg_start_thread(void *(*func)(void *), void *param);
char *mg_md5(char buf[33], ...);
int mg_authorize_digest(struct mg_connection *c, FILE *fp);
// Callback function return codes
enum { MG_REQUEST_NOT_PROCESSED, MG_REQUEST_PROCESSED, MG_REQUEST_CALL_AGAIN };
enum { MG_AUTH_FAIL, MG_AUTH_OK };
enum { MG_ERROR_NOT_PROCESSED, MG_ERROR_PROCESSED };
enum { MG_CLIENT_CONTINUE, MG_CLIENT_CLOSE };
// HTTP client events
enum {
MG_CONNECT_SUCCESS, MG_CONNECT_FAILURE,
MG_DOWNLOAD_SUCCESS, MG_DOWNLOAD_FAILURE
};
int mg_connect(struct mg_server *, const char *host, int port, int use_ssl,
mg_handler_t handler, void *param);
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // MONGOOSE_HEADER_INCLUDED

View file

@ -121,6 +121,7 @@
#include <Cockpit/cockpitDisplayManager.hxx>
#include <Network/HTTPClient.hxx>
#include <Network/fgcom.hxx>
#include <Network/http/httpd.hxx>
#include <Viewer/CameraGroup.hxx>
@ -767,6 +768,12 @@ void fgCreateSubsystems(bool duringReset) {
globals->add_subsystem("fgcom", new FGCom);
#endif
{
SGSubsystem * httpd = flightgear::http::FGHttpd::createInstance( fgGetNode(flightgear::http::PROPERTY_ROOT) );
if( NULL != httpd )
globals->add_subsystem("httpd", httpd );
}
////////////////////////////////////////////////////////////////////
// Initialize the lighting subsystem.
////////////////////////////////////////////////////////////////////

View file

@ -48,7 +48,7 @@
#include <Network/AV400Sim.hxx>
#include <Network/AV400WSim.hxx>
#include <Network/garmin.hxx>
#include <Network/httpd.hxx>
#include <Network/http/httpd.hxx>
#include <Network/igc.hxx>
#include <Network/jpg-httpd.hxx>
#include <Network/joyclient.hxx>
@ -149,10 +149,6 @@ FGIO::parse_port_config( const string& config )
} else if ( protocol == "igc" ) {
IGCProtocol *igc = new IGCProtocol;
io = igc;
} else if ( protocol == "httpd" ) {
// determine port
string port = tokens[1];
return new FGHttpd( atoi(port.c_str()) );
} else if ( protocol == "jpg-httpd" ) {
// determine port
int port = simgear::strutils::to_int(tokens[1]);

View file

@ -65,6 +65,7 @@
#include <Viewer/viewer.hxx>
#include <Viewer/viewmgr.hxx>
#include <Environment/presets.hxx>
#include <Network/http/httpd.hxx>
#include "AircraftDirVisitorBase.hxx"
#include <osg/Version>
@ -949,6 +950,16 @@ fgOptStartDateGmt( const char *arg )
return FG_OPTIONS_OK;
}
static int
fgOptHttpd( const char * arg )
{
int port = atoi(arg);
if( port > 0 ) {
fgSetInt( string(flightgear::http::PROPERTY_ROOT).append("/listening-port").c_str(), port );
}
return FG_OPTIONS_OK;
}
static int
fgSetupProxy( const char *arg )
{
@ -1554,7 +1565,7 @@ struct OptionDesc {
{"hud-culled", false, OPTION_STRING, "/sim/hud/frame-stat-type", false, "culled", 0 },
{"atcsim", true, OPTION_CHANNEL, "", false, "dummy", 0 },
{"atlas", true, OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
{"httpd", true, OPTION_CHANNEL, "", false, "", 0 },
{"httpd", true, OPTION_FUNC , "", false, "", fgOptHttpd },
{"jpg-httpd", true, OPTION_CHANNEL, "", false, "", 0 },
{"native", true, OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
{"native-ctrls", true, OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },

View file

@ -10,7 +10,6 @@ set(SOURCES
atlas.cxx
garmin.cxx
generic.cxx
httpd.cxx
HTTPClient.cxx
igc.cxx
joyclient.cxx
@ -27,7 +26,7 @@ set(SOURCES
pve.cxx
ray.cxx
rul.cxx
jpg-httpd.cxx
jpg-httpd.cxx
)
set(HEADERS
@ -40,7 +39,6 @@ set(HEADERS
atlas.hxx
garmin.hxx
generic.hxx
httpd.hxx
HTTPClient.hxx
igc.hxx
joyclient.hxx
@ -57,7 +55,7 @@ set(HEADERS
pve.hxx
ray.hxx
rul.hxx
jpg-httpd.hxx
jpg-httpd.hxx
)
if(ENABLE_IAX)
@ -71,3 +69,5 @@ if(RTI_FOUND)
add_subdirectory(HLA)
endif()
add_subdirectory(http)

View file

@ -0,0 +1,21 @@
include(FlightGearComponent)
set(SOURCES
httpd.cxx
ScreenshotUriHandler.cxx
PropertyUriHandler.cxx
JsonUriHandler.cxx
RunUriHandler.cxx
)
set(HEADERS
urihandler.hxx
httpd.hxx
ScreenshotUriHandler.hxx
PropertyUriHandler.hxx
JsonUriHandler.hxx
RunUriHandler.hxx
HTTPRequest.hxx
)
flightgear_component(Http "${SOURCES}" "${HEADERS}")

View file

@ -0,0 +1,65 @@
// HTTPRequest.hxx -- Wraps a http Request
//
// Written by Torsten Dreyer, started April 2014.
//
// Copyright (C) 2014 Torsten Dreyer
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifndef FG_HTTPREQUEST_HXX
#define FG_HTTPREQUEST_HXX
#include <string>
#include <map>
namespace flightgear {
namespace http {
class HTTPRequest
{
public:
HTTPRequest() {}
virtual ~HTTPRequest() {}
std::string Method;
std::string Uri;
std::string HttpVersion;
std::string QueryString;
std::string remoteAddress;
int remotePort;
std::string localAddress;
int localPort;
std::string Content;
class StringMap : public std::map<std::string,std::string> {
public:
std::string get( const std::string & key ) const {
const_iterator it = find( key );
return it == end() ? "" : it->second;
}
};
StringMap RequestVariables;
StringMap HeaderVariables;
};
}
} // namespace flightgear
#endif // FG_HTTPREQUEST_HXX

View file

@ -0,0 +1,51 @@
// HTTPResponse.hxx -- Wraps a http Response
//
// Written by Torsten Dreyer, started April 2014.
//
// Copyright (C) 2014 Torsten Dreyer
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifndef FG_HTTPRESPONSE_HXX
#define FG_HTTPRESPONSE_HXX
#include <string>
#include <map>
namespace flightgear {
namespace http {
class HTTPResponse
{
public:
HTTPResponse();
virtual ~HTTPResponse() {}
int StatusCode;
std::string Content;
typedef std::map<std::string,std::string> Header_t;
Header_t Header;
};
inline HTTPResponse::HTTPResponse() :
StatusCode(200)
{
}
}
} // namespace flightgear
#endif // FG_HTTPRESPONSE_HXX

View file

@ -0,0 +1,109 @@
// JsonUriHandler.cxx -- json interface to the property tree
//
// Written by Torsten Dreyer, started April 2014.
//
// Copyright (C) 2014 Torsten Dreyer
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "JsonUriHandler.hxx"
#include <Main/fg_props.hxx>
#include <simgear/props/props.hxx>
#include <3rdparty/cjson/cJSON.h>
using std::string;
namespace flightgear {
namespace http {
static const char * getPropertyTypeString( simgear::props::Type type )
{
switch( type ) {
case simgear::props::NONE: return "-";
case simgear::props::ALIAS: return "alias";
case simgear::props::BOOL: return "bool";
case simgear::props::INT: return "int";
case simgear::props::LONG: return "long";
case simgear::props::FLOAT: return "float";
case simgear::props::DOUBLE: return "double";
case simgear::props::STRING: return "string";
case simgear::props::UNSPECIFIED: return "unspecified";
case simgear::props::EXTENDED: return "extended";
case simgear::props::VEC3D: return "vec3d";
case simgear::props::VEC4D: return "vec4d";
default: return "?";
}
}
static cJSON * PropToJson( SGPropertyNode_ptr n )
{
cJSON * jsonProp = cJSON_CreateObject();
cJSON_AddItemToObject(jsonProp, "path", cJSON_CreateString(n->getPath().c_str()));
cJSON_AddItemToObject(jsonProp, "name", cJSON_CreateString(n->getDisplayName().c_str()));
cJSON_AddItemToObject(jsonProp, "value", cJSON_CreateString(n->getStringValue()));
cJSON_AddItemToObject(jsonProp, "type", cJSON_CreateString(getPropertyTypeString(n->getType())));
return jsonProp;
}
bool JsonUriHandler::handleGetRequest( const HTTPRequest & request, HTTPResponse & response )
{
response.Header["Content-Type"] = "application/json; charset=ISO-8859-1";
string propertyPath = request.Uri;
// strip the uri prefix of our handler
propertyPath = propertyPath.substr( getUri().size() );
// strip the querystring
size_t pos = propertyPath.find( '?' );
if( pos != string::npos ) {
propertyPath = propertyPath.substr( 0, pos-1 );
}
// skip trailing '/' - not very efficient but shouldn't happen too often
while( false == propertyPath.empty() && propertyPath[ propertyPath.length()-1 ] == '/' )
propertyPath = propertyPath.substr(0,propertyPath.length()-1);
SGPropertyNode_ptr node = fgGetNode( string("/") + propertyPath );
if( false == node.valid() ) {
response.StatusCode = 400;
response.Content = "Node not found: " + propertyPath;
SG_LOG(SG_NETWORK,SG_ALERT, response.Content );
return true;
}
cJSON * json = PropToJson( node );
if( node->nChildren() > 0 ) {
cJSON * jsonArray = cJSON_CreateArray();
for( int i = 0; i < node->nChildren(); i++ )
cJSON_AddItemToArray( jsonArray, PropToJson( node->getChild(i) ) );
cJSON_AddItemToObject( json, "children", jsonArray );
}
char * jsonString = cJSON_Print( json );
response.Content = jsonString;
free( jsonString );
cJSON_Delete( json );
return true;
}
} // namespace http
} // namespace flightgear

View file

@ -0,0 +1,38 @@
// JsonUriHandler.hxx -- json interface to the property tree
//
// Written by Torsten Dreyer, started April 2014.
//
// Copyright (C) 2014 Torsten Dreyer
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifndef __FG_JSON_URI_HANDLER_HXX
#define __FG_JSON_URI_HANDLER_HXX
#include "urihandler.hxx"
namespace flightgear {
namespace http {
class JsonUriHandler : public URIHandler {
public:
JsonUriHandler( const char * uri = "/json/" ) : URIHandler( uri ) {}
virtual bool handleGetRequest( const HTTPRequest & request, HTTPResponse & response );
};
} // namespace http
} // namespace flightgear
#endif //#define __FG_SCREENSHOT_URI_HANDLER_HXX

View file

@ -0,0 +1,411 @@
// PropertyUriHandler.cxx -- a web form interface to the property tree
//
// Written by Torsten Dreyer, started April 2014.
//
// Copyright (C) 2014 Torsten Dreyer
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "PropertyUriHandler.hxx"
#include <Main/fg_props.hxx>
#include <simgear/debug/logstream.hxx>
#include <simgear/misc/strutils.hxx>
#include <boost/lexical_cast.hpp>
#include <vector>
#include <map>
#include <algorithm>
#include <cstring>
using std::string;
using std::map;
using std::vector;
namespace flightgear {
namespace http {
class DOMElement {
public:
virtual ~DOMElement() {}
virtual std::string render() const = 0;
};
class DOMTextElement : public DOMElement {
public:
DOMTextElement( const string & text ) : _text(text) {}
virtual std::string render() const { return _text; }
private:
string _text;
};
class DOMNode : public DOMElement {
public:
DOMNode( const string & name ) : _name(name) {}
virtual ~DOMNode();
virtual std::string render() const;
virtual void addChild( DOMElement * child );
virtual void setAttribute( const string & name, const string & value );
protected:
string _name;
typedef vector<const DOMElement*> Children_t;
typedef map<string,string> Attributes_t;
Children_t _children;
Attributes_t _attributes;
};
DOMNode::~DOMNode()
{
for( Children_t::const_iterator it = _children.begin(); it != _children.end(); ++it )
delete *it;
}
string DOMNode::render() const
{
string reply;
reply.append( "<" ).append( _name );
for( Attributes_t::const_iterator it = _attributes.begin(); it != _attributes.end(); ++it ) {
reply.append( " " );
reply.append( it->first );
reply.append( "=\"" );
reply.append( it->second );
reply.append( "\"" );
}
if( _children.empty() ) {
reply.append( " />\r" );
return reply;
} else {
reply.append( ">" );
}
for( Children_t::const_iterator it = _children.begin(); it != _children.end(); ++it ) {
reply.append( (*it)->render() );
}
reply.append( "</" ).append( _name ).append( ">\r" );
return reply;
}
void DOMNode::addChild( DOMElement * child )
{
_children.push_back( child );
}
void DOMNode::setAttribute( const string & name, const string & value )
{
_attributes[name] = value;
}
class SortedChilds : public simgear::PropertyList {
public:
SortedChilds( SGPropertyNode_ptr node ) {
for (int i = 0; i < node->nChildren(); i++)
push_back(node->getChild(i));
std::sort(begin(), end(), CompareNodes());
}
private:
class CompareNodes {
public:
bool operator() (const SGPropertyNode *a, const SGPropertyNode *b) const {
int r = strcmp(a->getName(), b->getName());
return r ? r < 0 : a->getIndex() < b->getIndex();
}
};
};
static const char * getPropertyTypeString( simgear::props::Type type )
{
switch( type ) {
case simgear::props::NONE: return "";
case simgear::props::ALIAS: return "alias";
case simgear::props::BOOL: return "bool";
case simgear::props::INT: return "int";
case simgear::props::LONG: return "long";
case simgear::props::FLOAT: return "float";
case simgear::props::DOUBLE: return "double";
case simgear::props::STRING: return "string";
case simgear::props::UNSPECIFIED: return "unspecified";
case simgear::props::EXTENDED: return "extended";
case simgear::props::VEC3D: return "vec3d";
case simgear::props::VEC4D: return "vec4d";
default: return "?";
}
}
DOMElement * createHeader( const string & prefix, const string & propertyPath )
{
using namespace simgear::strutils;
string path = prefix;
DOMNode * root = new DOMNode( "div" );
root->setAttribute( "id", "breadcrumb" );
DOMNode * headline = new DOMNode( "h3" );
root->addChild( headline );
headline->addChild( new DOMTextElement("FlightGear Property Browser") );
DOMNode * breadcrumb = new DOMNode("ul");
root->addChild( breadcrumb );
DOMNode * li = new DOMNode("li");
breadcrumb->addChild( li );
DOMNode * a = new DOMNode("a");
li->addChild( a );
a->setAttribute( "href", path );
a->addChild( new DOMTextElement( "[root]" ) );
string_list items = split( propertyPath, "/" );
for( string_list::iterator it = items.begin(); it != items.end(); ++it ) {
if( (*it).empty() ) continue;
path.append( *it ).append( "/" );
li = new DOMNode("li");
breadcrumb->addChild( li );
a = new DOMNode("a");
li->addChild( a );
a->setAttribute( "href", path );
a->addChild( new DOMTextElement( (*it) ) );
}
return root;
}
static DOMElement * renderPropertyValueElement( SGPropertyNode_ptr node )
{
string value = node->getStringValue();
int len = value.length();
if( len < 15 ) len = 15;
DOMNode * root;
if( len < 60 ) {
root = new DOMNode( "input" );
root->setAttribute( "type", "text" );
root->setAttribute( "name", node->getDisplayName() );
root->setAttribute( "value", value );
root->setAttribute( "size", boost::lexical_cast<std::string>( len ) );
root->setAttribute( "maxlength", "2047" );
} else {
int rows = (len / 60)+1;
int cols = 60;
root = new DOMNode( "textarea" );
root->setAttribute( "name", node->getDisplayName() );
root->setAttribute( "cols", boost::lexical_cast<std::string>( cols ) );
root->setAttribute( "rows", boost::lexical_cast<std::string>( rows ) );
root->setAttribute( "maxlength", "2047" );
root->addChild( new DOMTextElement( value ) );
}
return root;
}
bool PropertyUriHandler::handleGetRequest( const HTTPRequest & request, HTTPResponse & response )
{
string propertyPath = request.Uri;
// strip the uri prefix of our handler
propertyPath = propertyPath.substr( getUri().size() );
// strip the querystring
size_t pos = propertyPath.find( '?' );
if( pos != string::npos ) {
propertyPath = propertyPath.substr( 0, pos-1 );
}
// skip trailing '/' - not very efficient but shouldn't happen too often
while( false == propertyPath.empty() && propertyPath[ propertyPath.length()-1 ] == '/' )
propertyPath = propertyPath.substr(0,propertyPath.length()-1);
if( request.RequestVariables.get("submit") == "update" ) {
// update leaf
string value = request.RequestVariables.get("value");
SG_LOG(SG_NETWORK,SG_INFO, "httpd: setting " << propertyPath << " to '" << value << "'" );
fgSetString( propertyPath.c_str(), value );
}
if( request.RequestVariables.get("submit") == "set" ) {
for( HTTPRequest::StringMap::const_iterator it = request.RequestVariables.begin(); it != request.RequestVariables.end(); ++it ) {
if( it->first == "submit" ) continue;
string pp = propertyPath + "/" + it->first;
SG_LOG(SG_NETWORK,SG_INFO, "httpd: setting " << pp << " to '" << it->second << "'" );
fgSetString( pp, it->second );
}
}
// build the response
DOMNode * html = new DOMNode( "html" );
html->setAttribute( "lang", "en" );
DOMNode * head = new DOMNode( "head" );
html->addChild( head );
DOMNode * e;
e = new DOMNode( "title" );
head->addChild( e );
e->addChild( new DOMTextElement( string("FlightGear Property Browser - ") + propertyPath ) );
e = new DOMNode( "link" );
head->addChild( e );
e->setAttribute( "href", "/css/props.css" );
e->setAttribute( "rel", "stylesheet" );
e->setAttribute( "type", "text/css" );
DOMNode * body = new DOMNode( "body" );
html->addChild( body );
SGPropertyNode_ptr node = fgGetNode( string("/") + propertyPath );
if( false == node.valid() ) {
DOMNode * headline = new DOMNode( "h3" );
body->addChild( headline );
headline->addChild( new DOMTextElement( "Non-existent node requested!" ) );
e = new DOMNode( "b" );
e->addChild( new DOMTextElement( propertyPath ) );
// does not exist
body->addChild( e );
} else if( node->nChildren() > 0 ) {
// Render the list of children
body->addChild( createHeader( getUri(), propertyPath ));
DOMNode * table = new DOMNode("table");
body->addChild( table );
DOMNode * tr = new DOMNode( "tr" );
table->addChild( tr );
DOMNode * th = new DOMNode( "th" );
tr->addChild( th );
th->addChild( new DOMTextElement( "&nbsp;" ) );
th = new DOMNode( "th" );
tr->addChild( th );
th->addChild( new DOMTextElement( "Property" ) );
th->setAttribute( "id", "property" );
th = new DOMNode( "th" );
tr->addChild( th );
th->addChild( new DOMTextElement( "Value" ) );
th->setAttribute( "id", "value" );
th = new DOMNode( "th" );
tr->addChild( th );
th->addChild( new DOMTextElement( "Type" ) );
th->setAttribute( "id", "type" );
SortedChilds sortedChilds( node );
for(SortedChilds::iterator it = sortedChilds.begin(); it != sortedChilds.end(); ++it ) {
tr = new DOMNode( "tr" );
table->addChild( tr );
SGPropertyNode_ptr child = *it;
string name = child->getDisplayName(true);
DOMNode * td;
// Expand Link
td = new DOMNode("td");
tr->addChild( td );
td->setAttribute( "id", "expand" );
if ( child->nChildren() > 0 ) {
DOMNode * a = new DOMNode("a");
td->addChild( a );
a->setAttribute( "href", getUri() + propertyPath + "/" + name );
a->addChild( new DOMTextElement( "(+)" ));
}
// Property Name
td = new DOMNode("td");
tr->addChild( td );
td->setAttribute( "id", "property" );
DOMNode * a = new DOMNode("a");
td->addChild( a );
a->setAttribute( "href", getUri() + propertyPath + "/" + name );
a->addChild( new DOMTextElement( name ) );
// Value
td = new DOMNode("td");
tr->addChild( td );
td->setAttribute( "id", "value" );
if ( child->nChildren() == 0 ) {
DOMNode * form = new DOMNode("form");
td->addChild( form );
form->setAttribute( "method", "GET" );
form->setAttribute( "action", getUri() + propertyPath );
e = new DOMNode( "input" );
form->addChild( e );
e->setAttribute( "type", "submit" );
e->setAttribute( "value", "set" );
e->setAttribute( "name", "submit" );
form->addChild( renderPropertyValueElement( node->getNode( name ) ) );
} else {
td->addChild( new DOMTextElement( "&nbsp;" ) );
}
// Property Type
td = new DOMNode("td");
tr->addChild( td );
td->setAttribute( "id", "type" );
td->addChild(
new DOMTextElement( getPropertyTypeString(node->getNode( name )->getType()) ) );
}
} else {
// Render a single property
body->addChild( createHeader( getUri(), propertyPath ));
e = new DOMNode( "div" );
body->addChild( e );
e->setAttribute( "id", "currentvalue" );
e->addChild( new DOMTextElement( "Current Value: " ) );
e->addChild( new DOMTextElement( node->getStringValue() ) );
DOMNode * form = new DOMNode("form");
body->addChild( form );
form->setAttribute( "method", "GET" );
form->setAttribute( "action", getUri() + propertyPath );
e = new DOMNode( "input" );
form->addChild( e );
e->setAttribute( "type", "submit" );
e->setAttribute( "value", "update" );
e->setAttribute( "name", "submit" );
form->addChild( renderPropertyValueElement( node ) );
}
// Send the response
response.Content = "<!DOCTYPE html>";
response.Content.append( html->render() );
delete html;
response.Header["Content-Type"] = "text/html; charset=ISO-8859-1";
return true;
}
} // namespace http
} // namespace flightgear

View file

@ -0,0 +1,38 @@
// PropertyUriHandler.cxx -- a web form interface to the property tree
//
// Written by Torsten Dreyer, started April 2014.
//
// Copyright (C) 2014 Torsten Dreyer
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifndef __FG_PROPERTY_URI_HANDLER_HXX
#define __FG_PROPERTY_URI_HANDLER_HXX
#include "urihandler.hxx"
namespace flightgear {
namespace http {
class PropertyUriHandler : public URIHandler {
public:
PropertyUriHandler( const char * uri = "/prop/" ) : URIHandler( uri ) {}
virtual bool handleGetRequest( const HTTPRequest & request, HTTPResponse & response );
};
} // namespace http
} // namespace flightgear
#endif //#define __FG_PROPERTY_URI_HANDLER_HXX

View file

@ -0,0 +1,55 @@
// RunUriHandler.cxx -- Run a flightgear command
//
// Written by Torsten Dreyer, started April 2014.
//
// Copyright (C) 2014 Torsten Dreyer
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "RunUriHandler.hxx"
#include <simgear/props/props.hxx>
#include <simgear/structure/commands.hxx>
#include <Main/globals.hxx>
using std::string;
namespace flightgear {
namespace http {
bool RunUriHandler::handleRequest( const HTTPRequest & request, HTTPResponse & response )
{
response.Header["Content-Type"] = "text/plain";
string command = request.RequestVariables.get("value");
if( command.empty() ) {
response.StatusCode = 400;
response.Content = "command not specified";
return true;
}
SGPropertyNode args;
if ( globals->get_commands()->execute(command.c_str(), &args) ) {
response.Content = "ok.";
return true;
}
response.Content = "command '" + command + "' failed.";
SG_LOG( SG_NETWORK, SG_ALERT, response.Content );
return true;
}
} // namespace http
} // namespace flightgear

View file

@ -0,0 +1,38 @@
// RunUriHandler.hxx -- Provide screenshots via http
//
// Written by Torsten Dreyer, started April 2014.
//
// Copyright (C) 2014 Torsten Dreyer
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifndef __FG_RUN_URI_HANDLER_HXX
#define __FG_RUN_URI_HANDLER_HXX
#include "urihandler.hxx"
namespace flightgear {
namespace http {
class RunUriHandler : public URIHandler {
public:
RunUriHandler( const char * uri = "/run.cgi" ) : URIHandler( uri ) {}
virtual bool handleRequest( const HTTPRequest & request, HTTPResponse & response );
};
} // namespace http
} // namespace flightgear
#endif //#define __FG_RUN_URI_HANDLER_HXX

View file

@ -0,0 +1,39 @@
// ScreenshotUriHandler.cxx -- Provide screenshots via http
//
// Written by Torsten Dreyer, started April 2014.
//
// Copyright (C) 2014 Torsten Dreyer
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "ScreenshotUriHandler.hxx"
using std::string;
namespace flightgear {
namespace http {
bool ScreenshotUriHandler::handleRequest( const HTTPRequest & request, HTTPResponse & response )
{
response.Header["Content-Type"] = "image/jpeg";
// string response = "Screenshot - not yet implemented :-(";
// mg_send_data( connection, response.c_str(), response.length() );
return true;
}
} // namespace http
} // namespace flightgear

View file

@ -0,0 +1,38 @@
// ScreenshotUriHandler.hxx -- Provide screenshots via http
//
// Written by Torsten Dreyer, started April 2014.
//
// Copyright (C) 2014 Torsten Dreyer
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifndef __FG_SCREENSHOT_URI_HANDLER_HXX
#define __FG_SCREENSHOT_URI_HANDLER_HXX
#include "urihandler.hxx"
namespace flightgear {
namespace http {
class ScreenshotUriHandler : public URIHandler {
public:
ScreenshotUriHandler( const char * uri = "/screenshot/" ) : URIHandler( uri ) {}
virtual bool handleRequest( const HTTPRequest & request, HTTPResponse & response );
};
} // namespace http
} // namespace flightgear
#endif //#define __FG_SCREENSHOT_URI_HANDLER_HXX

244
src/Network/http/httpd.cxx Normal file
View file

@ -0,0 +1,244 @@
// httpd.cxx -- a http daemon subsystem based on Mongoose http
//
// Written by Torsten Dreyer, started April 2014.
//
// Copyright (C) 2014 Torsten Dreyer
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "httpd.hxx"
#include "HTTPRequest.hxx"
#include "ScreenshotUriHandler.hxx"
#include "PropertyUriHandler.hxx"
#include "JsonUriHandler.hxx"
#include "RunUriHandler.hxx"
#include <Main/fg_props.hxx>
#include <Include/version.h>
#include <3rdparty/mongoose/mongoose.h>
#include <string>
#include <vector>
using std::string;
using std::vector;
namespace flightgear {
namespace http {
const char * PROPERTY_ROOT = "/sim/http";
class MongooseHttpd : public FGHttpd {
public:
MongooseHttpd( SGPropertyNode_ptr );
~MongooseHttpd();
void init();
void bind();
void unbind();
void shutdown();
void update( double dt );
private:
int requestHandler( struct mg_connection * );
static int staticRequestHandler( struct mg_connection * );
struct mg_server *_server;
SGPropertyNode_ptr _configNode;
typedef int (MongooseHttpd::*handler_t)( struct mg_connection * );
typedef vector<SGSharedPtr<URIHandler> > URIHandlerMap;
URIHandlerMap _uriHandlers;
};
MongooseHttpd::MongooseHttpd( SGPropertyNode_ptr configNode ) :
_server(NULL),
_configNode(configNode)
{
}
MongooseHttpd::~MongooseHttpd()
{
mg_destroy_server(&_server);
}
void MongooseHttpd::init()
{
SGPropertyNode_ptr n = _configNode->getNode("uri-handler");
if( n.valid() ) {
const char * uri;
if( (uri=n->getStringValue( "screenshot" ))[0] != 0 ) {
SG_LOG(SG_NETWORK,SG_INFO,"httpd: adding screenshot uri handler at " << uri );
_uriHandlers.push_back( new flightgear::http::ScreenshotUriHandler( uri ) );
}
if( (uri=n->getStringValue( "property" ))[0] != 0 ) {
SG_LOG(SG_NETWORK,SG_INFO,"httpd: adding screenshot property handler at " << uri );
_uriHandlers.push_back( new flightgear::http::PropertyUriHandler( uri ) );
}
if( (uri=n->getStringValue( "json" ))[0] != 0 ) {
SG_LOG(SG_NETWORK,SG_INFO,"httpd: adding json property handler at " << uri );
_uriHandlers.push_back( new flightgear::http::JsonUriHandler( uri ) );
}
if( (uri=n->getStringValue( "run" ))[0] != 0 ) {
SG_LOG(SG_NETWORK,SG_INFO,"httpd: adding run handler at " << uri );
_uriHandlers.push_back( new flightgear::http::RunUriHandler( uri ) );
}
}
_server = mg_create_server(this);
n = _configNode->getNode("options");
if( n.valid() ) {
string docRoot = n->getStringValue( "document-root", fgGetString("/sim/fg-root") );
if( docRoot[0] != '/' ) docRoot.insert(0,"/").insert(0,fgGetString("/sim/fg-root"));
mg_set_option(_server, "document_root", docRoot.c_str() );
mg_set_option(_server, "listening_port", n->getStringValue( "listening-port", "8080" ) );
// mg_set_option(_server, "url_rewrites", n->getStringValue( "url-rewrites", "" ) );
mg_set_option(_server, "enable_directory_listing", n->getStringValue( "enable-directory-listing", "yes" ) );
mg_set_option(_server, "idle_timeout_ms", n->getStringValue( "idle-timeout-ms", "30000" ) );
mg_set_option(_server, "index_files", n->getStringValue( "index-files", "index.html" ) );
}
mg_set_request_handler( _server, MongooseHttpd::staticRequestHandler );
}
void MongooseHttpd::bind()
{
}
void MongooseHttpd::unbind()
{
mg_destroy_server(&_server);
_uriHandlers.clear();
}
void MongooseHttpd::shutdown()
{
}
void MongooseHttpd::update( double dt )
{
mg_poll_server( _server, 0 );
}
class MongooseHTTPRequest : public HTTPRequest {
private:
inline string NotNull( const char * cp ) { return NULL == cp ? "" : cp; }
public:
MongooseHTTPRequest( struct mg_connection * connection ) {
Method = NotNull(connection->request_method);
Uri = urlDecode( NotNull(connection->uri));
HttpVersion = NotNull(connection->http_version);
QueryString = urlDecode(NotNull(connection->query_string));
remoteAddress = NotNull(connection->remote_ip);
remotePort = connection->remote_port;
localAddress = NotNull(connection->local_ip);
localPort = connection->local_port;
using namespace simgear::strutils;
string_list pairs = split(string(QueryString), "&");
for( string_list::iterator it = pairs.begin(); it != pairs.end(); ++it ) {
string_list nvp = split( *it, "=" );
if( nvp.size() != 2 ) continue;
RequestVariables.insert( make_pair( nvp[0], nvp[1] ) );
}
for( int i = 0; i < connection->num_headers; i++ )
HeaderVariables[connection->http_headers[i].name] = connection->http_headers[i].value;
Content = NotNull(connection->content);
}
string urlDecode( const string & s ) {
string r = "";
int max = s.length();
int a, b;
for ( int i = 0; i < max; i++ ) {
if ( s[i] == '+' ) {
r += ' ';
} else if ( s[i] == '%' && i + 2 < max
&& isxdigit(s[i + 1])
&& isxdigit(s[i + 2]) ) {
i++;
a = isdigit(s[i]) ? s[i] - '0' : toupper(s[i]) - 'A' + 10;
i++;
b = isdigit(s[i]) ? s[i] - '0' : toupper(s[i]) - 'A' + 10;
r += (char)(a * 16 + b);
} else {
r += s[i];
}
}
return r;
}
};
int MongooseHttpd::requestHandler( struct mg_connection * connection )
{
MongooseHTTPRequest request(connection);
HTTPResponse response;
response.Header["Server"] = "FlightGear/" FLIGHTGEAR_VERSION " Mongoose/" MONGOOSE_VERSION;
response.Header["Connection"] = "close";
response.Header["Cache-Control"] = "no-cache";
{
char buf[64];
time_t now = time(NULL);
strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now));
response.Header["Date"] = buf;
}
bool processed = false;
for( URIHandlerMap::iterator it = _uriHandlers.begin(); it != _uriHandlers.end(); ++it ) {
URIHandler * handler = *it;
const string uri = connection->uri;
if( uri.find( handler->getUri() ) == 0 ) {
processed = handler->handleRequest( request, response );
break;
}
}
if( processed ) {
for( HTTPResponse::Header_t::const_iterator it = response.Header.begin(); it != response.Header.end(); ++it ) {
const string name = it->first;
const string value = it->second;
if( name.empty() || value.empty() ) continue;
mg_send_header( connection, name.c_str(), value.c_str() );
}
mg_send_status( connection, response.StatusCode );
mg_send_data( connection, response.Content.c_str(), response.Content.length() );
}
return processed ? MG_REQUEST_PROCESSED : MG_REQUEST_NOT_PROCESSED;
}
int MongooseHttpd::staticRequestHandler( struct mg_connection * connection )
{
return static_cast<MongooseHttpd*>(connection->server_param)->requestHandler( connection );
}
FGHttpd * FGHttpd::createInstance( SGPropertyNode_ptr configNode )
{
return configNode.valid() ? new MongooseHttpd( configNode ) : NULL;
}
} // namespace http
} // namespace flightgear

View file

@ -1,9 +1,8 @@
// httpd.hxx -- FGFS http property manager interface / external script
// and control class
// httpd.hxx -- a http daemon subsystem based on Mongoose http
//
// Written by Curtis Olson, started June 2001.
// Written by Torsten Dreyer, started April 2014.
//
// Copyright (C) 2001 Curtis L. Olson - http://www.flightgear.org/~curt
// Copyright (C) 2014 Torsten Dreyer
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
@ -18,33 +17,28 @@
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifndef FG_HTTPD_HXX
#define FG_HTTPD_HXX
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/props/props.hxx>
#ifndef _FG_HTTPD_HXX
#define _FG_HTTPD_HXX
namespace flightgear {
namespace http {
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
extern const char * PROPERTY_ROOT;
#include "protocol.hxx"
class HttpdServer;
class FGHttpd : public FGProtocol
class FGHttpd : public SGSubsystem
{
int port;
HttpdServer *server;
public:
FGHttpd( int p );
~FGHttpd();
bool open();
bool process();
bool close();
static FGHttpd * createInstance( SGPropertyNode_ptr configNode );
};
#endif // _FG_HTTPD_HXX
}
} // namespace flightgear
#endif // FG_HTTPD_HXX

View file

@ -0,0 +1,61 @@
// urihandler.hxx -- a base class for URI handler
//
// Written by Torsten Dreyer, started April 2014.
//
// Copyright (C) 2014 Torsten Dreyer
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifndef __FG_URI_HANDLER_HXX
#define __FG_URI_HANDLER_HXX
#include "HTTPRequest.hxx"
#include "HTTPResponse.hxx"
#include <simgear/structure/SGReferenced.hxx>
#include <string>
#include <map>
namespace flightgear {
namespace http {
class URIHandler : public SGReferenced {
public:
URIHandler( const char * uri ) : _uri(uri) {}
virtual ~URIHandler() {}
virtual bool handleRequest( const HTTPRequest & request, HTTPResponse & response ) {
if( request.Method == "GET" ) return handleGetRequest( request, response );
if( request.Method == "PUT" ) return handlePutRequest( request, response );
return false;
}
virtual bool handleGetRequest( const HTTPRequest & request, HTTPResponse & response ) {
return false;
}
virtual bool handlePutRequest( const HTTPRequest & request, HTTPResponse & response ) {
return false;
}
const std::string & getUri() const { return _uri; }
private:
std::string _uri;
};
} // namespace http
} // namespace flightgear
#endif //#define __FG_URI_HANDLER_HXX

View file

@ -1,445 +0,0 @@
// httpd.cxx -- FGFS http property manager interface / external script
// and control class
//
// Written by Curtis Olson, started June 2001.
//
// Copyright (C) 2001 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <simgear/compiler.h>
#include <algorithm> // sort()
#include <cstdlib> // atoi() atof()
#include <cstring>
#include <cstdio>
#include <string>
#include <simgear/debug/logstream.hxx>
#include <simgear/io/sg_netChat.hxx>
#include <simgear/io/iochannel.hxx>
#include <simgear/math/sg_types.hxx>
#include <simgear/structure/commands.hxx>
#include <simgear/props/props.hxx>
#include <simgear/misc/strutils.hxx>
#include <Main/fg_props.hxx>
#include <Main/globals.hxx>
#include "httpd.hxx"
using std::string;
/* simple httpd server that makes an hasty stab at following the http
1.1 rfc. */
//////////////////////////////////////////////////////////////
// class HttpdChannel
//////////////////////////////////////////////////////////////
class HttpdChannel : public simgear::NetChat
{
simgear::NetBuffer buffer;
string urlEncode(string);
string urlDecode(string);
public:
HttpdChannel() : buffer(512) { setTerminator("\r\n"); }
virtual void collectIncomingData (const char* s, int n) {
buffer.append(s,n);
}
// Handle the actual http request
virtual void foundTerminator(void);
};
//////////////////////////////////////////////////////////////
// class HttpdServer
//////////////////////////////////////////////////////////////
class HttpdServer : private simgear::NetChannel
{
virtual bool writable (void) { return false; }
virtual void handleAccept (void) {
simgear::IPAddress addr;
int handle = accept ( &addr );
SG_LOG( SG_IO, SG_INFO, "Client " << addr.getHost() << ":" << addr.getPort() << " connected" );
HttpdChannel *hc = new HttpdChannel;
hc->setHandle ( handle );
poller.addChannel( hc );
}
simgear::NetChannelPoller poller;
public:
HttpdServer ( int port );
void poll()
{
poller.poll();
}
};
HttpdServer::HttpdServer(int port)
{
if (!open())
{
SG_LOG( SG_IO, SG_ALERT, "Failed to open HTTP port.");
return;
}
if (0 != bind( "", port ))
{
SG_LOG( SG_IO, SG_ALERT, "Failed to bind HTTP port.");
return;
}
if (0 != listen( 5 ))
{
SG_LOG( SG_IO, SG_ALERT, "Failed to listen on HTTP port.");
return;
}
poller.addChannel(this);
SG_LOG(SG_IO, SG_ALERT, "Httpd server started on port " << port);
}
//////////////////////////////////////////////////////////////
// class FGHttpd
//////////////////////////////////////////////////////////////
FGHttpd::FGHttpd(int p) :
port(p),
server(NULL)
{
}
FGHttpd::~FGHttpd()
{
delete server;
}
bool FGHttpd::open() {
if ( is_enabled() ) {
SG_LOG( SG_IO, SG_ALERT, "This shouldn't happen, but the channel "
<< "is already in use, ignoring" );
return false;
}
server = new HttpdServer( port );
set_hz( 15 ); // default to processing requests @ 15Hz
set_enabled( true );
return true;
}
bool FGHttpd::process() {
server->poll();
return true;
}
bool FGHttpd::close() {
if (!server)
return true;
SG_LOG( SG_IO, SG_INFO, "closing FGHttpd" );
delete server;
server = NULL;
set_enabled( false );
return true;
}
class CompareNodes {
public:
bool operator() (const SGPropertyNode *a, const SGPropertyNode *b) const {
int r = strcmp(a->getName(), b->getName());
return r ? r < 0 : a->getIndex() < b->getIndex();
}
};
static string makeLinksForPath( const string & request )
{
using namespace simgear::strutils;
string reply = "<A HREF=\"/\">/</A>";
string path = "/";
string_list sl = split( request, "/" );
for( string_list::iterator it = sl.begin(); it != sl.end(); ++it ) {
if( (*it).empty() ) continue;
path.append( *it ).append( "/" );
reply.append("<A HREF=\"")
.append(path)
.append("\">")
.append(*it)
.append("</A>/");
}
return reply;
}
// Handle http GET requests
void HttpdChannel::foundTerminator (void) {
closeWhenDone ();
const string s = buffer.getData();
if ( s.find( "GET " ) == 0 ) {
SG_LOG( SG_IO, SG_INFO, "echo: " << s );
string rest = s.substr(4);
string request;
string tmp;
string::size_type pos = rest.find( " " );
if ( pos != string::npos ) {
request = rest.substr( 0, pos );
} else {
request = "/";
}
SGPropertyNode *node = NULL;
pos = request.find( "?" );
if ( pos != string::npos ) {
// request to update property value
string args = request.substr( pos + 1 );
request = request.substr( 0, pos );
SG_LOG( SG_IO, SG_INFO, "'" << request << "' '" << args << "'" );
request = urlDecode(request);
// parse args looking for "value="
bool done = false;
while ( ! done ) {
string arg;
pos = args.find("&");
if ( pos != string::npos ) {
arg = args.substr( 0, pos );
args = args.substr( pos + 1 );
} else {
arg = args;
done = true;
}
SG_LOG( SG_IO, SG_INFO, " arg = " << arg );
string::size_type apos = arg.find("=");
if ( apos != string::npos ) {
string a = arg.substr( 0, apos );
string b = arg.substr( apos + 1 );
SG_LOG( SG_IO, SG_INFO, " a = " << a << " b = " << b );
if ( request == "/run.cgi" ) {
// execute a command
if ( a == "value" ) {
SGPropertyNode args;
if ( !globals->get_commands()
->execute(urlDecode(b).c_str(), &args) )
{
SG_LOG( SG_NETWORK, SG_ALERT,
"Command " << urlDecode(b)
<< " failed.");
}
}
} else {
if ( a == "value" ) {
// update a property value
fgSetString( request.c_str(),
urlDecode(b).c_str() );
}
}
}
}
} else {
request = urlDecode(request);
}
node = globals->get_props()->getNode(request.c_str());
string response = "";
response += "<HTML LANG=\"en\">";
response += getTerminator();
response += "<HEAD>";
response += getTerminator();
response += "<TITLE>FlightGear - ";
response += request;
response += "</TITLE>";
response += getTerminator();
response += "</HEAD>";
response += getTerminator();
response += "<BODY>";
response += getTerminator();
if (node == NULL) {
response += "<H3>Non-existent node requested!</H3>";
response += getTerminator();
response += "<B>";
response += request.c_str();
response += "</B> does not exist.";
response += getTerminator();
} else if ( node->nChildren() > 0 ) {
// request is a path with children
response += "<H3>Contents of \"";
response += makeLinksForPath( request );
response += "\"</H3>";
response += getTerminator();
vector<SGPropertyNode *> children;
for (int i = 0; i < node->nChildren(); i++)
children.push_back(node->getChild(i));
std::sort(children.begin(), children.end(), CompareNodes());
vector<SGPropertyNode *>::iterator it, end = children.end();
for (it = children.begin(); it != end; ++it) {
SGPropertyNode *child = *it;
string name = child->getDisplayName(true);
string line = "";
if ( child->nChildren() > 0 ) {
line += "<B><A HREF=\"";
line += request;
if ( request.substr(request.length() - 1, 1) != "/" ) {
line += "/";
}
line += urlEncode(name);
line += "\">";
line += name;
line += "</A></B>";
line += "/<BR>";
} else {
string value = node->getStringValue ( name.c_str(), "" );
line += "<B>";
line += name;
line += "</B> <A HREF=\"";
line += request;
if ( request.substr(request.length() - 1, 1) != "/" ) {
line += "/";
}
line += urlEncode(name);
line += "\">(";
line += value;
line += ")</A><BR>";
}
response += line;
response += getTerminator();
}
} else {
// request for an individual data member
string value = node->getStringValue();
response += "<form method=\"GET\" action=\"";
response += urlEncode(request);
response += "\">";
response += "<B>";
response += makeLinksForPath(request);
response += "</B> = ";
response += "<input type=text name=value size=\"15\" value=\"";
response += value;
response += "\" maxlength=2047>";
response += "<input type=submit value=\"update\" name=\"submit\">";
response += "</FORM>";
}
response += "</BODY>";
response += getTerminator();
response += "</HTML>";
response += getTerminator();
push( "HTTP/1.1 200 OK" );
push( getTerminator() );
SG_LOG( SG_IO, SG_INFO, "size = " << response.length() );
char ctmp[256];
sprintf(ctmp, "Content-Length: %u", (unsigned)response.length());
push( ctmp );
push( getTerminator() );
push( "Connection: close" );
push( getTerminator() );
push( "Content-Type: text/html" );
push( getTerminator() );
push( getTerminator() );
push( response.c_str() );
}
buffer.remove();
}
// encode everything but "a-zA-Z0-9_.-/" (see RFC2396)
string HttpdChannel::urlEncode(string s) {
string r = "";
for ( int i = 0; i < (int)s.length(); i++ ) {
if ( isalnum(s[i]) || s[i] == '_' || s[i] == '.'
|| s[i] == '-' || s[i] == '/' ) {
r += s[i];
} else {
char buf[16];
sprintf(buf, "%%%02X", (unsigned char)s[i]);
r += buf;
}
}
return r;
}
string HttpdChannel::urlDecode(string s) {
string r = "";
int max = s.length();
int a, b;
for ( int i = 0; i < max; i++ ) {
if ( s[i] == '+' ) {
r += ' ';
} else if ( s[i] == '%' && i + 2 < max
&& isxdigit(s[i + 1])
&& isxdigit(s[i + 2]) ) {
i++;
a = isdigit(s[i]) ? s[i] - '0' : toupper(s[i]) - 'A' + 10;
i++;
b = isdigit(s[i]) ? s[i] - '0' : toupper(s[i]) - 'A' + 10;
r += (char)(a * 16 + b);
} else {
r += s[i];
}
}
return r;
}