forked from mwan2013/ta
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathkvmessage.c
209 lines (182 loc) · 4.46 KB
/
kvmessage.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "libhttp.h"
#include "liburl.h"
#include "kvmessage.h"
/* Receives an HTTP request from socket SOCKFD and decodes it into KVREQ.
* Returns false if there is an error. */
bool kvrequest_receive(kvrequest_t *kvreq, int sockfd) {
bool success = false;
kvreq->type = EMPTY;
http_request_t req;
url_params_t params;
zero_params(¶ms);
success = http_request_receive(&req, sockfd);
if (!success)
goto error;
success = url_decode(¶ms, req.path);
if (!success)
goto error;
switch (req.method) {
case GET: {
kvreq->type = is_empty_str(params.key) ? INDEX : GETREQ;
break;
}
case PUT: {
if (is_empty_str(params.key) || is_empty_str(params.val))
goto error;
kvreq->type = PUTREQ;
break;
}
case DELETE: {
if (is_empty_str(params.key))
goto error;
kvreq->type = DELREQ;
break;
}
case POST: {
if (is_empty_str(params.path))
goto error;
if (!strcmp(params.path, REGISTER_PATH)) {
if (is_empty_str(params.key) || is_empty_str(params.val))
goto error;
kvreq->type = REGISTER;
} else if (!strcmp(params.path, COMMIT_PATH)) {
kvreq->type = COMMIT;
} else if (!strcmp(params.path, ABORT_PATH)) {
kvreq->type = ABORT;
}
break;
}
default:
goto error;
}
strcpy(kvreq->key, params.key);
strcpy(kvreq->val, params.val);
return true;
error:
return false;
}
/* Maps HTTP response codes to their corresponding msgtype_t for KVMessages.
* Returns EMPTY if the status code isn't supported. */
static msgtype_t kvresponse_get_status_code(short status) {
switch (status) {
case 200:
return GETRESP;
case 201:
return SUCCESS;
case 500:
return ERROR;
case 202:
return VOTE;
case 204:
return ACK;
default:
return EMPTY;
}
}
/* Receives an HTTP response from socket SOCKFD and decodes into KVRES.
* Returns false if there is an error. */
bool kvresponse_receive(kvresponse_t *kvres, int sockfd) {
bool success = false;
http_response_t res;
success = http_response_receive(&res, sockfd);
if (!success)
goto error;
kvres->type = kvresponse_get_status_code(res.status);
if (kvres->type == EMPTY)
goto error;
strcpy(kvres->body, res.body);
return true;
error:
return false;
}
http_method_t http_method_for_request_type(msgtype_t type) {
switch (type) {
case GETREQ:
return GET;
case PUTREQ:
return PUT;
case DELREQ:
return DELETE;
case REGISTER:
case COMMIT:
case ABORT:
return POST;
default:
return INVALID;
}
}
char *path_for_request_type(msgtype_t type) {
switch (type) {
case REGISTER:
return "register";
case COMMIT:
return "commit";
case ABORT:
return "abort";
default:
return "";
}
}
/* Sends REQ on socket SOCKFD. Returns the number of bytes which were sent, and
* 1 on error. */
int kvrequest_send(kvrequest_t *kvreq, int sockfd) {
http_method_t method = http_method_for_request_type(kvreq->type);
if (method == INVALID)
return -1;
url_params_t params;
strcpy(params.path, path_for_request_type(kvreq->type));
strcpy(params.key, kvreq->key);
strcpy(params.val, kvreq->val);
char url[HTTP_MSG_MAX_SIZE + 1];
url_encode(url, ¶ms);
http_outbound_t msg;
if (!http_outbound_init_request(&msg, sockfd, method, url))
return -1;
http_outbound_end_headers(&msg);
return http_outbound_send(&msg);
}
int http_code_for_response_type(msgtype_t type) {
switch (type) {
case GETRESP:
return 200;
case SUCCESS:
return 201;
case ERROR:
return 500;
case VOTE:
return 202;
case ACK:
return 204;
default:
return -1;
}
}
int kvresponse_send(kvresponse_t *kvres, int sockfd) {
int code = http_code_for_response_type(kvres->type);
if (code < 0)
return -1;
http_outbound_t msg;
if (!http_outbound_init_response(&msg, sockfd, code))
return -1;
char lenbuf[10] = "0";
if (strlen(kvres->body) > 0)
sprintf(lenbuf, "%ld", strlen(kvres->body));
http_outbound_add_header(&msg, "Content-Length", lenbuf);
http_outbound_end_headers(&msg);
http_outbound_add_string(&msg, kvres->body);
return http_outbound_send(&msg);
}
void kvrequest_clear(kvrequest_t *req) {
req->type = EMPTY;
memset(req->key, 0, MAX_KEYLEN + 1);
memset(req->val, 0, MAX_VALLEN + 1);
}
void kvresponse_clear(kvresponse_t *res) {
res->type = EMPTY;
memset(res->body, 0, KVRES_BODY_MAX_SIZE + 1);
}