/* Returns a url-decoded version of str */
/* IMPORTANT: be sure to free() the returned string after use */
char *url_decode(char *str) {
- char *pstr = str,
- *buf = malloc(strlen(str) + 1),
- *pbuf = buf;
+ size_t size = strlen(str) + 1;
+ char *buf = malloc(size);
if(!buf)
- fatal("Cannot allocate memory.");
+ fatal("Cannot allocate %zu bytes of memory.", size);
+
+ return url_decode_r(buf, str, size);
+}
+
+char *url_decode_r(char *to, char *url, size_t size) {
+ char *s = url, // source
+ *d = to, // destination
+ *e = &to[size - 1]; // destination end
- while (*pstr) {
- if (*pstr == '%') {
- if (pstr[1] && pstr[2]) {
- *pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]);
- pstr += 2;
+ while(*s && d < e) {
+ if(unlikely(*s == '%')) {
+ if(likely(s[1] && s[2])) {
+ *d++ = from_hex(s[1]) << 4 | from_hex(s[2]);
+ s += 2;
}
}
- else if (*pstr == '+')
- *pbuf++ = ' ';
+ else if(unlikely(*s == '+'))
+ *d++ = ' ';
else
- *pbuf++ = *pstr;
+ *d++ = *s;
- pstr++;
+ s++;
}
- *pbuf = '\0';
+ *d = '\0';
- return buf;
+ return to;
}
-
w->mode = WEB_CLIENT_MODE_NORMAL;
w->enable_gzip = 0;
w->keepalive = 0;
- if(w->decoded_url) {
- free(w->decoded_url);
- w->decoded_url = NULL;
- }
+ w->decoded_url[0] = '\0';
buffer_reset(w->response.header_output);
buffer_reset(w->response.header);
// http_request_validate()
// returns:
// = 0 : all good, process the request
-// > 0 : request is complete, but is not supported
+// > 0 : request is not supported
// < 0 : request is incomplete - wait for more data
static inline int http_request_validate(struct web_client *w) {
// find the SPACE + "HTTP/"
while(*s) {
- // find the space
+ // find the next space
while (*s && *s != ' ') s++;
// is it SPACE + "HTTP/" ?
}
// incomplete requests
- if(!*s) {
+ if(unlikely(!*s)) {
w->wait_receive = 1;
return -2;
}
// we have the end of encoded_url - remember it
char *ue = s;
+ // make sure we have complete request
+ // complete requests contain: \r\n\r\n
while(*s) {
// find a line feed
- while (*s && *s != '\r') s++;
+ while(*s && *s++ != '\r');
// did we reach the end?
if(unlikely(!*s)) break;
// is it \r\n ?
- if (likely(s[1] == '\n')) {
+ if(likely(*s++ == '\n')) {
// is it again \r\n ? (header end)
- if(unlikely(s[2] == '\r' && s[3] == '\n')) {
+ if(unlikely(*s == '\r' && s[1] == '\n')) {
// a valid complete HTTP request found
*ue = '\0';
- w->decoded_url = url_decode(encoded_url);
+ url_decode_r(w->decoded_url, encoded_url, URL_MAX + 1);
*ue = ' ';
+
+ // copy the URL - we are going to overwrite parts of it
+ // FIXME -- we should avoid it
+ strncpyz(w->last_url, w->decoded_url, URL_MAX);
w->wait_receive = 0;
return 0;
}
// another header line
- s = http_header_parse(w, &s[2]);
+ s = http_header_parse(w, s);
}
- else s++;
}
// incomplete request
else { // what_to_do == 0
gettimeofday(&w->tv_in, NULL);
- // copy the URL - we are going to overwrite parts of it
- // FIXME -- we should avoid it
- strncpyz(w->last_url, w->decoded_url, URL_MAX);
-
if(w->mode == WEB_CLIENT_MODE_OPTIONS) {
code = 200;
w->response.data->contenttype = CT_TEXT_PLAIN;
char client_ip[NI_MAXHOST+1];
char client_port[NI_MAXSERV+1];
- char last_url[URL_MAX+1];
+ char decoded_url[URL_MAX + 1]; // we decode the URL in this buffer
+ char last_url[URL_MAX+1]; // we keep a copy of the decoded URL here
struct timeval tv_in, tv_ready;
int mode;
int keepalive;
int enable_gzip;
- char *decoded_url;
struct sockaddr_storage clientaddr;