Better client/cmd relationship.

master
Nicolas Favre-Felix 14 years ago
parent 1073b847ba
commit a298d3c16b

@ -118,6 +118,9 @@ http_client_cleanup(struct http_client *c) {
memset(&c->verb, 0, sizeof(c->verb));
cmd_free(c->cmd);
c->cmd = NULL;
c->state = CLIENT_WAITING;
}

@ -7,6 +7,7 @@
#include "http.h"
struct server;
struct cmd;
typedef enum {
CLIENT_WAITING,
@ -21,6 +22,7 @@ struct http_client {
struct event ev;
struct server *s;
client_state state;
struct cmd *cmd;
/* http parser */
http_parser_settings settings;

11
cmd.c

@ -14,11 +14,10 @@
#include <ctype.h>
struct cmd *
cmd_new(struct http_client *client, int count) {
cmd_new(int count) {
struct cmd *c = calloc(1, sizeof(struct cmd));
c->client = client;
c->count = count;
c->argv = calloc(count, sizeof(char*));
@ -31,6 +30,8 @@ cmd_new(struct http_client *client, int count) {
void
cmd_free(struct cmd *c) {
if(!c) return;
free(c->argv);
free(c->argv_len);
@ -95,7 +96,7 @@ cmd_run(struct server *s, struct http_client *client,
param_count++;
}
cmd = cmd_new(client, param_count);
client->cmd = cmd = cmd_new(param_count);
/* get output formatting function */
uri_len = cmd_select_format(client, cmd, uri, uri_len, &f_format);
@ -128,7 +129,7 @@ cmd_run(struct server *s, struct http_client *client,
/* no args (e.g. INFO command) */
if(!slash) {
redisAsyncCommandArgv(s->ac, f_format, cmd, 1, cmd->argv, cmd->argv_len);
redisAsyncCommandArgv(s->ac, f_format, client, 1, cmd->argv, cmd->argv_len);
return 0;
}
p = slash + 1;
@ -156,7 +157,7 @@ cmd_run(struct server *s, struct http_client *client,
}
/* push command to Redis. */
redisAsyncCommandArgv(s->ac, f_format, cmd, cmd->count, cmd->argv, cmd->argv_len);
redisAsyncCommandArgv(s->ac, f_format, client, cmd->count, cmd->argv, cmd->argv_len);
for(i = 1; i < cur_param; ++i) {
free((char*)cmd->argv[i]);

@ -18,7 +18,6 @@ struct cmd {
int count;
const char **argv;
size_t *argv_len;
struct http_client *client;
int started_responding;
@ -33,7 +32,7 @@ struct subscription {
};
struct cmd *
cmd_new(struct http_client *client, int count);
cmd_new(int count);
void
cmd_free(struct cmd *c);

@ -30,10 +30,12 @@ char *etag_new(const char *p, size_t sz) {
}
void
format_send_reply(struct cmd *cmd, const char *p, size_t sz, const char *content_type) {
format_send_reply(struct http_client *client, const char *p, size_t sz, const char *content_type) {
int free_cmd = 1;
struct cmd *cmd = client->cmd;
if(cmd_is_subscribe(cmd)) {
free_cmd = 0;
@ -41,32 +43,32 @@ format_send_reply(struct cmd *cmd, const char *p, size_t sz, const char *content
if(cmd->started_responding == 0) {
const char *ct = cmd->mime?cmd->mime:content_type;
cmd->started_responding = 1;
http_set_header(&cmd->client->output_headers.content_type, ct, strlen(ct));
http_send_reply_start(cmd->client, 200, "OK");
http_set_header(&client->output_headers.content_type, ct, strlen(ct));
http_send_reply_start(client, 200, "OK");
}
http_send_reply_chunk(cmd->client, p, sz);
http_send_reply_chunk(client, p, sz);
} else {
/* compute ETag */
char *etag = etag_new(p, sz);
const char *if_none_match = cmd->client->input_headers.if_none_match.s;
const char *if_none_match = client->input_headers.if_none_match.s;
/* check If-None-Match */
if(if_none_match && strncmp(if_none_match, etag, cmd->client->input_headers.if_none_match.sz) == 0) {
if(if_none_match && strncmp(if_none_match, etag, client->input_headers.if_none_match.sz) == 0) {
/* SAME! send 304. */
http_send_reply(cmd->client, 304, "Not Modified", NULL, 0);
http_send_reply(client, 304, "Not Modified", NULL, 0);
} else {
const char *ct = cmd->mime?cmd->mime:content_type;
http_set_header(&cmd->client->output_headers.content_type, ct, strlen(ct));
http_set_header(&cmd->client->output_headers.etag, etag, strlen(etag));
http_send_reply(cmd->client, 200, "OK", p, sz);
http_set_header(&client->output_headers.content_type, ct, strlen(ct));
http_set_header(&client->output_headers.etag, etag, strlen(etag));
http_send_reply(client, 200, "OK", p, sz);
}
free(etag);
}
/* cleanup */
if(free_cmd) {
cmd_free(cmd);
cmd_free(client->cmd);
}
}

@ -3,9 +3,11 @@
#include <stdlib.h>
struct cmd;
struct http_client;
void
format_send_reply(struct cmd *cmd, const char *p, size_t sz, const char *content_type);
format_send_reply(struct http_client *client,
const char *p, size_t sz,
const char *content_type);
#endif

@ -12,7 +12,7 @@ void
custom_type_reply(redisAsyncContext *c, void *r, void *privdata) {
redisReply *reply = r;
struct cmd *cmd = privdata;
struct http_client *client = privdata;
(void)c;
char int_buffer[50];
int int_len;
@ -21,26 +21,26 @@ custom_type_reply(redisAsyncContext *c, void *r, void *privdata) {
return;
}
if(cmd->mime) { /* use the given content-type, but only for strings */
if(client->cmd->mime) { /* use the given content-type, but only for strings */
switch(reply->type) {
case REDIS_REPLY_NIL: /* or nil values */
format_send_reply(cmd, "", 0, cmd->mime);
format_send_reply(client, "", 0, client->cmd->mime);
return;
case REDIS_REPLY_STRING:
format_send_reply(cmd, reply->str, reply->len, cmd->mime);
format_send_reply(client, reply->str, reply->len, client->cmd->mime);
return;
case REDIS_REPLY_INTEGER:
int_len = sprintf(int_buffer, "%lld", reply->integer);
format_send_reply(cmd, int_buffer, int_len, cmd->mime);
format_send_reply(client, int_buffer, int_len, client->cmd->mime);
return;
}
}
/* couldn't make sense of what the client wanted. */
http_send_reply(cmd->client, 400, "Bad request", NULL, 0);
cmd_free(cmd);
http_send_reply(client, 400, "Bad request", NULL, 0);
cmd_free(client->cmd);
}

@ -15,12 +15,12 @@ void
json_reply(redisAsyncContext *c, void *r, void *privdata) {
redisReply *reply = r;
struct cmd *cmd = privdata;
struct http_client *client = privdata;
json_t *j;
char *jstr;
(void)c;
if(cmd == NULL) {
if(client->cmd == NULL) {
/* broken connection */
return;
}
@ -30,13 +30,15 @@ json_reply(redisAsyncContext *c, void *r, void *privdata) {
}
/* encode redis reply as JSON */
j = json_wrap_redis_reply(cmd, r);
j = json_wrap_redis_reply(client->cmd, r);
/* get JSON as string, possibly with JSONP wrapper */
jstr = json_string_output(j, cmd);
jstr = json_string_output(j,
client->query_string.jsonp.s,
client->query_string.jsonp.sz);
/* send reply */
format_send_reply(cmd, jstr, strlen(jstr), "application/json");
format_send_reply(client, jstr, strlen(jstr), "application/json");
/* cleanup */
json_decref(j);
@ -107,22 +109,20 @@ json_wrap_redis_reply(const struct cmd *cmd, const redisReply *r) {
char *
json_string_output(json_t *j, struct cmd *cmd) {
json_string_output(json_t *j, const char *jsonp, size_t jsonp_len) {
char *json_reply = json_dumps(j, JSON_COMPACT);
/* check for JSONP */
if(cmd->client->query_string.jsonp.s) {
if(jsonp) {
size_t json_len = strlen(json_reply);
size_t val_len = cmd->client->query_string.jsonp.sz;
size_t ret_len = val_len + 1 + json_len + 3;
size_t ret_len = jsonp_len + 1 + json_len + 3;
char *ret = calloc(1 + ret_len, 1);
memcpy(ret, cmd->client->query_string.jsonp.s, val_len);
ret[val_len]='(';
memcpy(ret + val_len + 1, json_reply, json_len);
memcpy(ret + val_len + 1 + json_len, ");\n", 3);
memcpy(ret, jsonp, jsonp_len);
ret[jsonp_len]='(';
memcpy(ret + jsonp_len + 1, json_reply, json_len);
memcpy(ret + jsonp_len + 1 + json_len, ");\n", 3);
free(json_reply);
return ret;

@ -11,6 +11,6 @@ void
json_reply(redisAsyncContext *c, void *r, void *privdata);
char *
json_string_output(json_t *j, struct cmd *cmd);
json_string_output(json_t *j, const char *jsonp, size_t jsonp_len);
#endif

@ -1,5 +1,4 @@
#include "raw.h"
#include "cmd.h"
#include "common.h"
#include "http.h"
@ -14,7 +13,7 @@ void
raw_reply(redisAsyncContext *c, void *r, void *privdata) {
redisReply *reply = r;
struct cmd *cmd = privdata;
struct http_client *client = privdata;
char *raw_out;
size_t sz;
(void)c;
@ -26,7 +25,7 @@ raw_reply(redisAsyncContext *c, void *r, void *privdata) {
raw_out = raw_wrap(r, &sz);
/* send reply */
format_send_reply(cmd, raw_out, sz, "binary/octet-stream");
format_send_reply(client, raw_out, sz, "binary/octet-stream");
/* cleanup */
free(raw_out);

Loading…
Cancel
Save