// ---------------------------------------------------------------------------- // the callback used to format data (into text, json, html, etc.) for clients // ---------------------------------------------------------------------------- // HTTP/1.1 200 OK // Content-type:text/plain // Transfer-Encoding: chunked // // 3c; // KEY:time VAL:Mon, 12 Mar 2012 13:11:49 GMT|KEY:00 VAL:14.03 // 3c; // KEY:time VAL:Mon, 12 Mar 2012 13:11:49 GMT|KEY:00 VAL:40.75 // 3c; // KEY:time VAL:Mon, 12 Mar 2012 13:11:49 GMT|KEY:00 VAL:45.02 // 0 // static int push_fn(char *argv[], xbuf_t *reply) { reply->len = 0; // empty buffer xbuf_xcat(reply, " \r\n" // room for chunck size: "1a; " "KEY:time VAL:%s|", (char*)get_env(argv, SERVER_DATE)); // fill the 2D HTML <table> cells with our 1D array // (we randomly skip some cells to avoid updating all of them) { int i = 0, r = 0, c = 0; while(i < CELLS) { if(!(sw_rand(&rnd) & 3)) // skip some cells xbuf_xcat(reply, "KEY:%c%c VAL:%.02f|", '0' + r, '0' + c, s_data[i++]); if(c + 1 < COLS) c++; else { c = 0; if(r + 1 < ROWS) r++; else r = 0; } } } reply->ptr[--reply->len] = 0; // remove the ending '|' // now we know it, setup the chunk size char *p = reply->ptr; int i = s_snprintf(p, 8, "%x;", reply->len - (sizeof(" \r\n") - 2)); p[i] = ' '; // useful for tracing, when we puts(reply->ptr); later xbuf_ncat(reply, "\r\n", sizeof("\r\n") - 1); // close this chunk return 1; }
int main(int argc, char *argv[]) { xbuf_t *reply = get_reply(argv); xbuf_xcat(reply, "<h3>main()'s argv[0-%d] listed:</h3>", argc ? argc - 1 : 0); u32 i = 0; while(i < argc) { xbuf_xcat(reply, "argv[%u] '%s'<br>", i, argv[i]); i++; } return 200; }
int main(int argc, char *argv[]) { static char msg[] = "Throttling Enabled @ %u KB/s!"; xbuf_xcat(get_reply(argv), msg, SPEED); throttle_reply(argv, SPEED, SPEED, 1); // 1: global setting, 0:this connection return 200; // return an HTTP code (200:'OK') }
int main(int argc, char *argv[]) { xbuf_xcat(get_reply(argv), "<br>" "<b>Servlet name</b>:<br>'%s'<br><br>" "<b>Client address</b>:<br>'%s'<br>", argv[-2], argv[-1]); return 200; }
// ---------------------------------------------------------------------------- int main(int argc, char *argv[]) { xbuf_t *reply = get_reply(argv); // encode string char buf[80], user[80] = "*****@*****.**"; int ret = s_snprintf(buf, 255, "%B", user); xbuf_xcat(reply, "<p>plain text %s to base64:<br> %s (len: %d)</p>", user, buf, ret); // decode string ret = s_snprintf(user, 255, "%-B", buf); xbuf_xcat(reply, "<p>base64 %s to plain text:<br> %s (len: %d)</p>", buf, user, ret); // encode binary data memset(user, 0, 8); ret = s_snprintf(buf, 255, "%8B", user); xbuf_xcat(reply, "<p>8 null bytes to base64:<br> %s (len: %d)</p>", buf, ret); // decode binary data memset(user, 'A', 16); ret = s_snprintf(user, 255, "%-B", buf); xbuf_xcat(reply, "<p>base64 %s to binary:<br> %s (len: %d)</p>", buf, memcmp(user, "\0\0\0\0\0\0\0", 8) ? "mismatch" : "OK, match", ret); // dump binary data int i = 0; while(i < 16) xbuf_xcat(reply, "user[%d] = %d<br>", i, user[i]), i++; return 200; // return an HTTP code (200:'OK') }
void getCallback(redisAsyncContext *c, void *r, void *privdata) { redisReply *reply = r; if (reply == NULL) return; gw_req_async_t *async = (gw_req_async_t *)privdata; xbuf_xcat(async->reply, "%x\r\n%s\r\n", reply->len, reply->str); // now unlock to main() light_unlock(&async->lock); // Disconnect after receiving the reply to GET redisAsyncDisconnect(c); }
int main(int argc, char *argv[]) { u32 *old_entity_size = (u32*)get_env(argv, MAX_ENTITY_SIZE); u32 new_entity_size = 200 * 1024; // 200 KiB xbuf_xcat(get_reply(argv), "<pre>\n" "Old entity size: %llk\n" "New entity size: %llk\n" // "New entity size: 200.00 KiB" "</pre>", *old_entity_size, new_entity_size); *old_entity_size = new_entity_size; // raise the limit to 200 KiB return 200; // return an HTTP code (200:'OK') }
void flushHeaders(void) { this->ptrHeaderSize = 0; xbuf_xcat ( this->httpOut, "HTTP/1.1 200 OK\r\n" "%s" "Content-type: %s\r\n" "Content-Length: %n\r\n" "Connection: close\r\n\r\n", (char *) this->headers.c_str(), (char *) this->contentType.c_str(), &ptrHeaderSize ); this->headersSet = true; this->headersSize = this->httpOut->len; }
int main(int argc, char *argv[]) { xbuf_t data; xbuf_init(&data); xbuf_cat(&data, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi sit amet " "quam purus, vitae fermentum turpis. Nam in augue mi. Donec suscipit moles" "tie felis, eget rhoncus risus pharetra in. Sed id diam id felis fringilla" " adipiscing non vitae odio. Etiam vulputate tristique elit, nec eleifend" " mauris scelerisque eu. Vestibulum luctus, enim a luctus posuere, mauris" " mauris rutrum mi, eget fermentum massa tortor id enim. Nulla feugiat " "porta urna quis laoreet. Morbi metus ante, commodo quis dictum vitae, " "rhoncus a libero. Cras viverra feugiat orci id interdum. Duis pulvinar " "neque id erat adipiscing facilisis. Maecenas vitae urna risus, euismod" " sollicitudin risus." ); char gzipped[4096]; u32 len = zlib_cmp(data.ptr, 0, data.len, gzipped, sizeof(gzipped), 1); printf("Original length: %i\n", data.len); printf("Gzipped length: %i\n\n", len); xbuf_t *reply = get_reply(argv); xbuf_xcat(reply, "HTTP/1.1 200 OK\r\n" "Content-Type: text/plain\r\n" "Content-Length: %i\r\n" "Content-Encoding: gzip\r\n\r\n", len ); xbuf_ncat(reply, gzipped, len); xbuf_free(&data); return -1; //custom headers }
int main(int argc, char *argv[]) { // get the server 'reply' buffer where to write our answer to the client xbuf_t *reply = get_reply(argv); // ------------------------------------------------------------------------- // step 1: setup a per-request context // ------------------------------------------------------------------------- void **data = (void**)get_env(argv, US_REQUEST_DATA); if(!data[0]) // we did not setup our per-request counter yet { data[0] = (void*)1; // use the persistent pointer as a simple counter char head[] = "HTTP/1.1 200 OK\r\n" "Connection: close\r\n" "Content-length: 60\r\n" // 3 * 20 characters "Content-type: text/plain; charset=utf-8\r\n" "\r\n\r\n"; xbuf_ncat(reply, head, sizeof(head) - 1); } // ------------------------------------------------------------------------- // step 2: repeatedly send to client an incremental reply // ------------------------------------------------------------------------- xbuf_xcat(reply, "partial reply %llu<br>\n", data[0]++); // ------------------------------------------------------------------------- // 3: decide when to stop streaming // ------------------------------------------------------------------------- if(data[0] > (void*)NBR_CHUNKS) { data[0] = 0; return RC_NOHEADERS; // RC_NOHEADERS: do not generate HTTP headers } // RC_NOHEADERS: do not generate HTTP headers // RC_STREAMING: call me again after send() is done return RC_NOHEADERS + RC_STREAMING; }
int list_threads(kv_item *item, xbuf_t *reply) { Thread *thread = (Thread*)item->val; xbuf_t thread_li; xbuf_init(&thread_li); //using sprintf-like formatting xbuf_xcat(&thread_li, "<li>" "<a href='/?forum_simple/act=t/id=%llu'>%s</a> (%lu)" "</li>", thread->id, thread->title.ptr, thread->posts.nbr_items ); char *pos = (char*)xbuf_findstr(reply, "<!--tpl-->"); if (pos) xbuf_insert(reply, pos, thread_li.len, thread_li.ptr); xbuf_free(&thread_li); return 1; }
int main(int argc, char *argv[]) { data_t **Data =(data_t **) get_env(argv, US_VHOST_DATA) , *data = NULL; xbuf_t *reply = get_reply ( argv ); switch(init_data(argv, Data)) { case 0: data = *Data; break; case 1: return 500; default: return 503; } char *uid; int auth = gw_is_member(argv, data, &uid); /** YOUR CODE GOES HERE */ xbuf_xcat(reply, "Hello World! auth: %d\n", auth); // Validate int GW_LOG("GW_VAL_IS_INT"); gw_val_cond_t *cond = gw_val_cond_new("-", GW_VAL_IS_INT); gw_validate_field(&cond, 1); printf("cond->field: %s\n", cond->field); printf("cond->type: %d\n", cond->type); printf("cond->is_valid: %s\n", (cond->is_valid) ? "true" : "false"); // Validate length GW_LOG("GW_VAL_LEN"); gw_val_cond_set(cond, "ssss", GW_VAL_LEN); cond->len.min = 10; cond->len.max = 0; gw_validate_field(&cond, 1); printf("cond->field: %s\n", cond->field); printf("cond->type: %d\n", cond->type); printf("cond->is_valid: %s\n", (cond->is_valid) ? "true" : "false"); // Validate email GW_LOG("GW_VAL_IS_EMAIL"); gw_val_cond_set(cond, "*****@*****.**", GW_VAL_IS_EMAIL); gw_validate_field(&cond, 1); printf("cond->field: %s\n", cond->field); printf("cond->type: %d\n", cond->type); printf("cond->is_valid: %s\n", (cond->is_valid) ? "true" : "false"); // Cleaning data if(auth == true) free(uid); free(cond); return 200; }
int main(int argc, char *argv[]) { xbuf_xcat(get_reply(argv), "%s", get_env(argv, REMOTE_ADDR)); return 200; }
// ---------------------------------------------------------------------------- int main(int argc, char *argv[]) { xbuf_t *reply = get_reply(argv); http_t *http = (void*)get_env(argv, HTTP_HEADERS); // ------------------------------------------------------------------------- // here you could count repeated attempts from the same IP address and then // take measures like blacklisting offenders (using G-WAN's TCP/IP firewall) // ------------------------------------------------------------------------- // u32 client_ip = (u32)get_env(argv, REMOTE_BIN_ADDR); // binary // char *client_ip = (char*)get_env(argv, REMOTE_ADDR); // string // ------------------------------------------------------------------------- // first (unauthorized) client request or something went bad // ------------------------------------------------------------------------- // /?auth_digest might be called by rogue clients, without G-WAN having // received (and validated) an authorization request if(http->h_auth_type != AUTH_BASIC) goto ask_new_auth; // ------------------------------------------------------------------------- // find the request parameters we need (auth_type is double-checked here // but that's to show how to implement a generic valid_user() function // aimed at being used with a database or an LDAP server) // ------------------------------------------------------------------------- static char *auth_types[] = { [AUTH_BAD] = "", [AUTH_ANY] = "*", [AUTH_BASIC] = "Basic", [AUTH_DIGEST] = "Digest", [AUTH_SRP] = "SRP", [AUTH_X509] = "x509" }; if(http->h_auth_type < AUTH_BASIC // check before you lookup auth_types[] || http->h_auth_type > AUTH_X509) http->h_auth_type = AUTH_BAD; char *auth = auth_types[http->h_auth_type]; char *meth = (char*)get_env(argv, REQUEST); // "GET /?auth_digest" char *uri = strchr(meth, ' '); // ^ if(uri) uri++; // pass space character // ------------------------------------------------------------------------- // check if the user is authorized (if not, send 401) // ------------------------------------------------------------------------- if(!valid_user(http->h_auth_user, http->h_auth_pwd, auth, uri, meth)) goto ask_new_auth; // ------------------------------------------------------------------------- // user is authorized, produce contents, redirect to contents, etc. // ------------------------------------------------------------------------- xbuf_xcat(reply, "<h1>Basic AUTHORIZATION</h1><p>Successfully authorized" " user: <tt>'%s'</tt>, password: <tt>'%s'</tt></p>", http->h_auth_user, http->h_auth_pwd); return 200; // return an HTTP code (200:'OK') // ------------------------------------------------------------------------- // first (unauthorized) client request or something went bad // ------------------------------------------------------------------------- ask_new_auth: // let G-WAN generate a 401 server reply with the authorization we want http->h_auth_type = AUTH_BASIC; return 401; // "401 Unauthorized" }
// ---------------------------------------------------------------------------- // imported functions: // get_reply(): get a pointer on the 'reply' dynamic buffer from the server // getus(): get current time in microseconds (1 millisecond = 1,000 us) // get_env(): get connection's 'environment' variables from the server // xbuf_cat(): like strcat(), but it works in the specified dynamic buffer // gif_build(): build an in-memory GIF image from a bitmap and palette // ---------------------------------------------------------------------------- int main(int argc, char *argv[]) { // ------------------------------------------------------------------------- // get a pointer on the server reply // ------------------------------------------------------------------------- xbuf_t *reply = get_reply(argv); // ------------------------------------------------------------------------- // allocate memory for a raw bitmap // ------------------------------------------------------------------------- int w = 800, h = 800, nbcolors = 256, wXh = w * h; u8 *bmp = (u8*)malloc(wXh); if(!bmp) return 503; // service unavailable // ------------------------------------------------------------------------- // render the Mandelbrot set in our bitmap // ------------------------------------------------------------------------- fractals(bmp, w, h, nbcolors); // ------------------------------------------------------------------------- // display the palette (useful when playing with 'tabcol[]' values) // ------------------------------------------------------------------------- { #define ROUND(a) ((a) > 0 ? (int)((a)+0.5) : -(int)(0.5-(a))) u8 *p = bmp; int i = h, wd20 = w / 20; float color = 0, col = (float)nbcolors / (float)h; while(i--) { color += col; memset(p, ROUND(color) & 255, wd20); p += w; } } // ------------------------------------------------------------------------- // build a smooth multi-gradient color palette from the fixed values below // ------------------------------------------------------------------------- static rgb_t tabcol[]={ { 0, 0, 128}, // Med. Blue { 0, 100, 200}, // Light Blue {100, 160, 160}, // Cyan { 0, 220, 100}, // Green {255, 255, 0}, // Yellow {255, 128, 0}, // Orange {128, 0, 0}, // Med. Red { 64, 0, 0}, // Dark Red {128, 0, 0}, // Med. Red {255, 128, 0}, // Orange {255, 255, 0}, // Yellow { 0, 220, 100}, // Green {100, 160, 160}, // Cyan { 0, 100, 200}, // Light Blue { 0, 0, 128}, // Med. Blue { 64, 0, 0}, // Dark Red {128, 0, 0}, // Med. Red {255, 128, 0}, // Orange {255, 255, 0}, // Yellow { 0, 220, 100}, // Green {100, 160, 160}, // Cyan { 0, 100, 200}, // Light Blue { 0, 0, 128}, // Med. Blue { 0, 0, 64}, // Dark Blue }, *tab = tabcol; // ------------------------------------------------------------------------- // just for fun, select different colors for each call // ------------------------------------------------------------------------- static u32 call = 0; u32 ncols = sizeof(tabcol) / sizeof(rgb_t); switch(call) { case 0: tab = tabcol; ncols = 10; break; // blue case 1: tab = &tabcol[ 4]; ncols = 10; break; // yellow case 2: tab = &tabcol[ 7]; ncols = 7; break; // dark red case 3: tab = &tabcol[ 1]; ncols = 16; break; // rainbow - } call = (call + 1) & 3; // generate the palette with our defined gradient steps u8 pal[768]; dr_gradient(pal, nbcolors, tab, ncols); // nice palete but we want a black body to delimit the mandelbrot set memset(pal + ((nbcolors - (nbcolors / 16)) * 3), 0, (nbcolors / 16) * 3); // ------------------------------------------------------------------------- // create custom HTTP response headers to send a GIF file // ------------------------------------------------------------------------- // (G-WAN automatically generates headers if none are provided but it can't // guess all MIME types so this automatic feature is for 'text/html' only // ...unless you explicitly specify the reply buffer MIME type) #ifdef BUILD_CUSTOM_HEADERS // old way of doing things // get the current HTTP date (like "Wed, 02 Jun 2010 06:49:37 GMT") u8 *date = (u8*)get_env(argv, SERVER_DATE); xbuf_xcat(reply, "HTTP/1.1 200 OK\r\n" "Date: %s\r\n" "Last-Modified: %s\r\n" "Content-type: image/gif\r\n" "Content-Length: \r\n" // make room for the for GIF length "Connection: close\r\n\r\n", date, date); // ------------------------------------------------------------------------- // make sure that we have enough space in the 'reply' buffer // (we are going to fill it directly from gif_build(), not via xbuf_xxx) // ------------------------------------------------------------------------- // (if we have not enough memory, we will get a 'graceful' crash) if(reply->allocated < (wXh / 10)) // very gross approximation { if(!xbuf_growto(reply, wXh / 10)) // resize reply { xbuf_init(reply); xbuf_ncat(reply, " ", 1); reply->len = 0; // discart pointless data, keep allocated memory return 503; // error: we could not allocate enough memory } } // ------------------------------------------------------------------------- // save the place where to patch the void 'Content-Length' HTTP Header // ------------------------------------------------------------------------- char *p = reply->ptr + reply->len - (sizeof("\r\nConnection: close\r\n\r\n") - 1); // ------------------------------------------------------------------------- // append a GIF image (-1:no transparency, 0: no comment) to 'reply' // ------------------------------------------------------------------------- int len = gif_build((u8*)(reply->ptr + reply->len), bmp, w, h, pal, nbcolors, -1, 0); if(len < 0) len = 0; // (len == -1) if gif_build() failed reply->len += len; // add the GIF size to the 'reply' buffer length free(bmp); // ------------------------------------------------------------------------- // store the GIF size in the empty space of the 'Content-Length' header // ------------------------------------------------------------------------- u32toa(p, len); #else // #ifdef BUILD_CUSTOM_HEADERS // works with any supported MIME type // ------------------------------------------------------------------------- // specify a MIME type so we don't have to build custom HTTP headers // ------------------------------------------------------------------------- char *mime = (char*)get_env(argv, REPLY_MIME_TYPE); // note that we setup the FILE EXTENTION, not the MIME type: mime[0] = '.'; mime[1] = 'g'; mime[2] = 'i'; mime[3] = 'f'; mime[4] = 0; // ------------------------------------------------------------------------- // make sure that we have enough space in the 'reply' buffer // (we are going to fill it directly from gif_build(), not via xbuf_xxx) // ------------------------------------------------------------------------- // (if we have not enough memory, we will get a 'graceful' crash) if(reply->allocated < (wXh / 10)) // very gross approximation { if(!xbuf_growto(reply, wXh / 10)) // resize reply { xbuf_init(reply); xbuf_ncat(reply, " ", 1); reply->len = 0; // discart pointless data, keep allocated memory return 503; // error: we could not allocate enough memory } } // ------------------------------------------------------------------------- // append a GIF image (-1:no transparency, 0: no comment) to 'reply' // ------------------------------------------------------------------------- int len = gif_build((u8*)(reply->ptr + reply->len), bmp, w, h, pal, nbcolors, -1, 0); if(len < 0) len = 0; // (len == -1) if gif_build() failed reply->len += len; // add the GIF size to the 'reply' buffer length free(bmp); #endif // #else #ifdef BUILD_CUSTOM_HEADERS return 200; // return an HTTP code (200:'OK') }
// ---------------------------------------------------------------------------- // imported functions: // get_reply(): get a pointer on the 'reply' dynamic buffer from the server // get_env(): get connection's 'environment' variables from the server // xbuf_cat(): like strcat(), but it works in the specified dynamic buffer // gif_build(): build an in-memory GIF image from a bitmap and palette // ---------------------------------------------------------------------------- int main(int argc, char *argv[]) { // ------------------------------------------------------------------------- // build the top of our HTML page // ------------------------------------------------------------------------- static char top[]= "<!DOCTYPE HTML>" "<html lang=\"en\"><head><title>Captcha</title><meta http-equiv" "=\"Content-Type\" content=\"text/html; charset=utf-8\">" "<link href=\"/imgs/style.css\" rel=\"stylesheet\" type=\"text/css\">" "</head><body style=\"margin:0 16px;\"><br><h2>Captcha for Humans</h2>" "<p>Please enter the SUM of all the GREEN FIGURES (not letters) below " "(that's twice the same image, just with a different HTML background " "- the Data-URI-inlined GIF background is transparent):</p><br>\r\n"; xbuf_t *reply = get_reply(argv); xbuf_ncat(reply, top, sizeof(top) - 1); // ------------------------------------------------------------------------- // allocate memory for a raw bitmap // ------------------------------------------------------------------------- const int w = BMP_WIDTH, h = BMP_HEIGHT, wXh = w * h; u8 *bmp = (u8*)calloc(CHAR_WIDTH * w, h); if(!bmp) return 503; // service unavailable // ------------------------------------------------------------------------- // render the captcha in our bitmap // ------------------------------------------------------------------------- u32 seed = (u32)getns(); prnd_t rnd; // pseudo-random generator (period: 1 << 158) sw_init(&rnd, seed); // EPOCH time in nano-seconds // structure needed by G-WAN's frame buffer routines like dr_text() bmp_t img ={ .bmp = bmp, .p = bmp, .bbp = 8, .pen = 1, .bgd = 0, .rect = {0,0, w,h}, .flags = 0, .w = w, .h = h, .x = 0, .y = 0 }; u32 sum = captcha(&img, &rnd); // ------------------------------------------------------------------------- // build the GIF image, gif_build(0:transparent color index, 0: no comment) // ------------------------------------------------------------------------- u8 pal[] = { 255, 255, 255, 223, 255, 191, 132, 164, 100, 0, 0, 0 }; const int nbcolors = (sizeof(pal) / sizeof(u8)) / 3; // RGB values u8 *gif = (u8*)malloc(CHAR_WIDTH * wXh); if(!gif) { free(bmp); return 503; } // service unavailable int gln = gif_build(gif, bmp, w, h, pal, nbcolors, 0, 0); // ------------------------------------------------------------------------- // store the base64 encoded GIF in the 'reply' buffer // ------------------------------------------------------------------------- if(gln > 0) // (gln == -1) if gif_build() failed { // a real captcha test would only display the first of those two views: // (they are shown side-by-side to visualize the background trick) xbuf_cat(reply, "<table><tr>\r\n" "<td style=\"background:#dfffbf;\">\r\n"); u32 img_pos = reply->len; xbuf_xcat(reply, "<img src=\"data:image/gif;base64,%*B\" alt=\"A tree\" " "width=\"%d\" height=\"%d\" /></td>\r\n", gln, gif, w + w, h + h); // scale picture xbuf_xcat(reply, "<td style=\"background:#84a464;\">%.*s</tr>\r\n</table>\n\r", reply->len - img_pos, reply->ptr + img_pos); } free(gif); free(bmp); // ------------------------------------------------------------------------- // close our HTML page // ------------------------------------------------------------------------- xbuf_xcat(reply, "<br>The two sums are: <b>%u</b> and <b>%u</b>... " "for the same Captcha image!<br><br>" "By just changing the <b>HTML background color</b> (mouse cursor " "hovering, previous state or input or shared secret) used for " "the transparent GIF Captcha image we can make something simple " "for humans become difficult or even completely impossible " "for robots.<br><br>" "HTML and GIF are served with one single request: the picture" " is generated on-the-fly and embedded into the HTML code by " " using the base64 encoding (look at the HTML source code)." "<br></body></html>", (sum & 0xffff0000) >> 16, sum & 0x0000ffff); return 200; // return an HTTP code (200:'OK') }