Skip to content

Instantly share code, notes, and snippets.

@Neopallium
Created March 20, 2011 06:21
Show Gist options
  • Save Neopallium/878156 to your computer and use it in GitHub Desktop.
Save Neopallium/878156 to your computer and use it in GitHub Desktop.
mongrel2 json gen speed-up.
#if 1
#define B(K, V) if((V) != NULL) { \
vstr = json_escape(V); \
bcatcstr(headers, ",\""); \
bcatcstr(headers, bdata(K)); \
bcatcstr(headers, "\":\""); \
bcatcstr(headers, bdata(vstr)); \
bcatcstr(headers, "\""); \
bdestroy(vstr); \
}
#else
#define B(K, V) if((V) != NULL) { \
vstr = json_escape(V); \
bformata(headers, ",\"%s\":\"%s\"", bdata(K), bdata(vstr)); \
bdestroy(vstr); \
}
#endif
static struct tagbstring QUOTE_CHAR = bsStatic("\"");
static struct tagbstring QUOTE_REPLACE = bsStatic("\\\"");
static struct tagbstring BSLASH_CHAR = bsStatic("\\");
static struct tagbstring BSLASH_REPLACE = bsStatic("\\\\");
static inline bstring json_escape(bstring in)
{
if(in == NULL) return NULL;
// TODO: this isn't efficient at all, make it better
bstring vstr = bstrcpy(in);
// MUST GO IN THIS ORDER
bfindreplace(vstr, &BSLASH_CHAR, &BSLASH_REPLACE, 0);
bfindreplace(vstr, &QUOTE_CHAR, &QUOTE_REPLACE, 0);
return vstr;
}
struct tagbstring JSON_LISTSEP = bsStatic("\",\"");
bstring Request_to_payload(Request *req, bstring uuid, int fd, const char *buf, size_t len)
{
bstring headers = bformat("{\"%s\":\"%s\"", bdata(&HTTP_PATH), bdata(req->path));
bstring result = NULL;
int id = Register_id_for_fd(fd);
bstring vstr = NULL; // used in the B macro
bstring key = NULL;
hnode_t *i = NULL;
hscan_t scan;
struct bstrList *val_list = NULL;
//ballocmin(headers, 8192);
check(id != -1, "Asked to generate a paylod for an fd that doesn't exist: %d", fd);
hash_scan_begin(&scan, req->headers);
for(i = hash_scan_next(&scan); i != NULL; i = hash_scan_next(&scan)) {
val_list = hnode_get(i);
key = (bstring)hnode_getkey(i);
if(val_list->qty > 1) {
// join all the values together as a json array then add that to the key
bstring list = bjoin(val_list, &JSON_LISTSEP);
#if 0
bformata(headers, ",\"%s\":[\"%s\"]", bdata(key), bdata(list));
#else
bcatcstr(headers, ",\"");
bcatcstr(headers, bdata(key));
bcatcstr(headers, "\":[\"");
bcatcstr(headers, bdata(list));
bcatcstr(headers, "\"]");
#endif
bdestroy(list);
} else {
B(key, val_list->entry[0]);
}
}
// these come after so that if anyone attempts to hijack these somehow, most
// hash algorithms languages have will replace the browser ones with ours
if(Request_is_json(req)) {
B(&HTTP_METHOD, &JSON_METHOD);
} else if(Request_is_xml(req)) {
B(&HTTP_METHOD, &XML_METHOD);
} else {
B(&HTTP_METHOD, req->request_method);
}
B(&HTTP_VERSION, req->version);
B(&HTTP_URI, req->uri);
B(&HTTP_QUERY, req->query_string);
B(&HTTP_FRAGMENT, req->fragment);
B(&HTTP_PATTERN, req->pattern);
bconchar(headers, '}');
result = bformat("%s %d %s %d:%s,%d:", bdata(uuid), id,
bdata(Request_path(req)),
blength(headers), bdata(headers), len);
bcatblk(result, buf, len);
bconchar(result, ',');
check(result, "Failed to construct payload result.");
bdestroy(headers);
return result;
error:
bdestroy(headers);
bdestroy(result);
return NULL;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment