// File: http_support.cpp // Author: Karl Abrahamson #include #include #include "rb_support.h" #include "http_support.h" using namespace std; static char hex_char(const char *digs); static void unmangle(const char *src, char *result); static bool matches_to(const char* str1, const char* str2, char c); static void get_up_to(const char* from, char c, char* to, int to_len); /************************************************ * WriteHttpHeading * ************************************************ * Begin a reply to a form query from an HTML * * form. * ************************************************/ void WriteHttpHeading() { cout << "Content-Type: text/html\r\n\r\n"; } /************************************************ * getBinding * ************************************************ * Suppose that data is the form of string that * * is passed to a program by an HTTP server via * * the Common Gateway Interface. It has the * * form * * name=val&name=val&... * * telling what was typed into boxes in a form. * * For example, if the form has two boxes * * called FLAVOR and COLOR, and somebody * * typed mango into the FLAVOR box and orange * * into the COLOR box, then data the string * * will be * * FLAVOR=mango&COLOR=orange * * * * getBinding(name, data) returns the string * * that was typed into the box called name. * * For example, * * getBinding("COLOR", * * "FLAVOR=mango&COLOR=orange"); * * returns "orange". * * * * The returned string is stored in memory that * * is allocated using 'new'. * ************************************************/ char* getBinding(const char* name, const char* data) { int j = 0; while(true) { while(isspace(data[j])) j++; if(data[j] == '\0') return NULL; if(matches_to(name, data + j, '=')) { const char* p = strchr(data + j, '='); if(p != NULL) { char buff1[MAX_DATA_LENGTH], buff2[MAX_DATA_LENGTH]; get_up_to(p+1, '&', buff1, MAX_DATA_LENGTH); unmangle(buff1, buff2); return duplicateString(buff2); } else return NULL; } else { while(data[j] != '&' && data[j] != '\0') j++; if(data[j] == '&') j++; } } } /************************************************ * hex_char * ************************************************ * digs is an array of two hexadecimal digits. * * Return the number that they represent. For * * example, "2A" represents 2*16 + 10 = 42. * ************************************************/ static char hex_char(const char *digs) { int result; char digcpy[3]; digcpy[0] = digs[0]; digcpy[1] = digs[1]; digcpy[2] = '\0'; sscanf(digcpy, "%x", &result); return (char) result; } /************************************************ * unmangle * ************************************************ * This function undoes transformations that a * * web browser does to a string. The * * transformations that are undone are as * * follows. * * * * 1. Each space is replaced by as + * * * * 2. A special character is replaced by %XX, * * where XX is the hexadecimal code for the * * character. For example, ':' is replaced * * by %3A. * * * * To undo those transformation, this function * * replaces each + by a space and each %XX by * * the character whose code is given. * * * * This function does the transformation on * * string src, and copies the result string * * into array result. Both are null-terminated.* * Array result must be allocated by the caller.* ************************************************/ static void unmangle(const char *src, char *result) { char *res_p; /* Pointer into result */ const char *src_p; /* Pointer into src */ res_p = result; src_p = src; while(*src_p != '\0') { /*--------------------* * Handle + => space. * *--------------------*/ if(*src_p == '+') { *(res_p++) = ' '; src_p++; } /*-------------* * Handle %XX. * *-------------*/ else if(*src_p == '%') { *(res_p++) = hex_char(src_p + 1); src_p += 3; } /*-----------------------------------* * Default: just copy the character. * *-----------------------------------*/ else *(res_p++) = *(src_p++); } /*----------------------------* * Null-terminate the result. * *----------------------------*/ *res_p = '\0'; } /************************************************ * matches_to * ************************************************ * Let P(s,c) be the prefix of s up to but not * * including the first occurrence of character * * c (or all of s if s does not include c). * * For example, P("abcde", 'd') = "abc" and * * P("abcde", 'z') = "abcde". * * * * matches_to(str1, str2, c) returns true if * * string str1 is the same as string P(str2, c).* * So, for example, * * matches_to("abc", "abc=e", '=') * * is true. * ************************************************/ static bool matches_to(const char* str1, const char* str2, char c) { int k; for(k = 0; str1[k] != '\0'; k++) { if(str1[k] != str2[k]) return false; } return str2[k] == c || str2[k] == '\0'; } /************************************************ * get_up_to * ************************************************ * get_up_to(from, c, to, to_len) gets the * * prefix of null-terminated string 'from' up * * to but not including the first occurrence of * * character c, and stores that string into * * array 'to'. The 'to' array is null- * * terminated. * * * * Parameter 'to_len' is the physical length of * * array 'to'. No more than that many total * * bytes are stored. * ************************************************/ static void get_up_to(const char* from, char c, char* to, int to_len) { int k; for(k = 0; from[k] != '\0' && from[k] != c && k < to_len - 1; k++) { to[k] = from[k]; } to[k] = '\0'; }