1 // HTTP server and client 2 3 #define HTTP_LIMIT 4096 4 #define HTTP_TIME 15000 5 #define HTTP_LISTEN 28888 6 #define HTTP_HDRS 64 7 #define HTTP_PORT 80 8 9 enum 10 { 11 HTTP_R_NONE = 0, 12 HTTP_R_OK = 200, 13 HTTP_R_NOTFOUND = 404 14 }; 15 16 enum 17 { 18 HTTP_S_START = 0, 19 HTTP_S_HEADERS, 20 HTTP_S_DATA, 21 HTTP_S_RESPONSE, 22 HTTP_S_DONE, 23 HTTP_S_FAILED, 24 HTTP_S_CONNECTING, 25 HTTP_S_MAX 26 }; 27 28 enum 29 { 30 HTTP_T_ERROR = 0, 31 HTTP_T_GET, 32 HTTP_T_POST, 33 HTTP_T_PUT, 34 HTTP_T_DELETE, 35 HTTP_T_MAX 36 }; 37 38 enum 39 { 40 HTTP_C_NONE = 0, 41 HTTP_C_URLENC, 42 HTTP_C_JSON, 43 HTTP_C_DATA, 44 HTTP_C_MAX 45 }; 46 47 struct httppair 48 { 49 string name, value; 50 httppairhttppair51 httppair() 52 { 53 name[0] = value[0] = 0; 54 } httppairhttppair55 httppair(const char *n, const char *v) 56 { 57 copystring(name, n); 58 copystring(value, v); 59 } ~httppairhttppair60 ~httppair() {} 61 }; 62 63 struct httpvars 64 { 65 vector<httppair> values; 66 httpvarshttpvars67 httpvars() { reset(); } ~httpvarshttpvars68 ~httpvars() {} 69 resethttpvars70 void reset() 71 { 72 values.shrink(0); 73 } 74 addhttpvars75 httppair &add() 76 { 77 return values.add(); 78 } 79 addhttpvars80 httppair &add(const char *name, const char *value) 81 { 82 return values.add(httppair(name, value)); 83 } 84 findhttpvars85 httppair *find(const char *name) 86 { 87 loopv(values) if(!strcasecmp(name, values[i].name)) return &values[i]; 88 return NULL; 89 } 90 gethttpvars91 const char *get(const char *name) 92 { 93 httppair *v = find(name); 94 if(v) return v->value; 95 return NULL; 96 } 97 lengthhttpvars98 int length() 99 { 100 return values.length(); 101 } 102 }; 103 104 struct httpreq 105 { 106 ENetAddress address; 107 ENetSocket socket; 108 int state, reqtype, contype; 109 string name; 110 bigstring path, input; 111 vector<char> output; 112 int inputpos, outputpos, conlength; 113 enet_uint32 lastactivity; 114 httpvars inhdrs, outhdrs, vars; 115 httpreqhttpreq116 httpreq() { reset(); } ~httpreqhttpreq117 ~httpreq() {} 118 resethttpreq119 void reset() 120 { 121 state = HTTP_S_START; 122 reqtype = HTTP_T_ERROR; 123 contype = HTTP_C_NONE; 124 name[0] = path[0] = 0; 125 inputpos = outputpos = conlength = 0; 126 lastactivity = 0; 127 output.shrink(0); 128 inhdrs.reset(); 129 outhdrs.reset(); 130 vars.reset(); 131 } 132 rawhttpreq133 void raw(const char c) 134 { 135 output.add(c); 136 } 137 138 void send(const char *msg, int len = 0) 139 { 140 if(!len) len = strlen(msg); 141 output.put(msg, len); 142 output.put("\r\n", 2); 143 } 144 sendfhttpreq145 void sendf(const char *fmt, ...) 146 { 147 bigstring msg; 148 va_list args; 149 va_start(args, fmt); 150 vformatstring(msg, fmt, args); 151 va_end(args); 152 send(msg); 153 } 154 }; 155 156 struct httpclient; 157 typedef void (__cdecl *httpcb)(httpclient *c); 158 struct httpclient : httpreq 159 { 160 int port, uid; 161 httpcb callback; 162 bigstring data; 163 httpclienthttpclient164 httpclient() { reset(); } ~httpclienthttpclient165 ~httpclient() {} 166 resethttpclient167 void reset() 168 { 169 port = 0; 170 uid = -1; 171 data[0] = 0; 172 callback = NULL; 173 httpreq::reset(); 174 } 175 }; 176 177 struct httpcmd; 178 typedef void (__cdecl *httpfun)(httpreq *r); 179 struct httpcmd 180 { 181 const char *name; 182 httpfun fun; 183 httpcmdhttpcmd184 httpcmd() {} namehttpcmd185 httpcmd(const char *n, void *f = NULL) : name(n), fun((httpfun)f) {} 186 }; 187 188 #define HTTP(name, fun) UNUSED static bool __http_##fun = http::addcommand(name, (httpfun)fun) 189 190 #define JSON_TOKENS 1024 191 192 enum 193 { 194 JSON_INIT = 0, 195 JSON_OBJECT, 196 JSON_ARRAY, 197 JSON_STRING, 198 JSON_PRIMITIVE, 199 JSON_MAX 200 }; 201 202 struct jsobj 203 { 204 string name, data; 205 int type; 206 vector<jsobj *> children; 207 jsobjjsobj208 jsobj() { reset(); } ~jsobjjsobj209 ~jsobj() { clear(); } 210 clearjsobj211 void clear() 212 { 213 children.deletecontents(); 214 } 215 resetjsobj216 void reset() 217 { 218 name[0] = data[0] = 0; 219 type = JSON_INIT; 220 children.shrink(0); 221 } 222 }; 223 224 namespace http 225 { 226 extern char *urldecode(char *dst, const char *str, size_t len); 227 extern int vardecode(const char *str, httpvars &vars); 228 extern bool addcommand(const char *name, httpfun fun); 229 extern httpclient *retrieve(const char *serv, int port, int type, const char *path, httpcb callback, const char *data = NULL, int uid = -1); 230 extern void cleanup(); 231 extern void init(); 232 extern void runframe(); 233 } 234 235 namespace json 236 { 237 extern int print(jsobj *j, char *dst, int level, size_t len); 238 extern jsobj *load(const char *str); 239 } 240