/* Returns 0 on success and nonzero on failure. */ int http_parse_status_line(const char *line, struct http_response *response) { const char *p, *q; http_response_init(response); /* Version. */ p = parse_http_version(line, &response->version); if (p == line) return -1; while (*p == ' ') p++; /* Status code. */ errno = 0; response->code = parse_long(p, (char **) &q); if (errno != 0 || q == p) return -1; p = q; /* Reason phrase. */ while (*p == ' ') p++; q = p; while (!is_crlf(q)) q++; /* We expect that the CRLF ends the string. */ if (*skip_crlf(q) != '\0') return -1; response->phrase = mkstr(p, q); return 0; }
/* See section 4.2 of RFC 2616 for header format. */ int http_parse_header(struct http_header **result, const char *header) { const char *p, *q; size_t value_len, value_offset; struct http_header *node, **prev; *result = NULL; prev = result; p = header; while (*p != '\0' && !is_crlf(p)) { /* Get the field name. */ q = p; while (*q != '\0' && is_token_char(*q)) q++; if (*q != ':') { http_header_free(*result); return 400; } node = (struct http_header *) safe_malloc(sizeof(*node)); node->name = mkstr(p, q); node->value = NULL; node->next = NULL; value_len = 0; value_offset = 0; /* Copy the header field value until we hit a CRLF. */ p = q + 1; p = skip_lws(p); for (;;) { q = p; while (*q != '\0' && !is_space_char(*q) && !is_crlf(q)) { /* Section 2.2 of RFC 2616 disallows control characters. */ if (iscntrl((int) (unsigned char) *q)) { http_header_node_free(node); return 400; } q++; } strbuf_append(&node->value, &value_len, &value_offset, p, q - p); p = skip_lws(q); if (is_crlf(p)) break; /* Replace LWS with a single space. */ strbuf_append_str(&node->value, &value_len, &value_offset, " "); } *prev = node; prev = &node->next; p = skip_crlf(p); } return 0; }
static int cs_read_chunk(const char *buf, int i, int len) { /* inside chunked body .. */ while (1) { int chunk_len = 0; #if CHUNK_DEBUG if (i < len-2) { int j; printf ("\n<<<"); for (j = i; j <= i+3; j++) printf ("%c", buf[j]); printf (">>>\n"); } #endif /* read chunk length */ while (1) if (i >= len-2) { #if CHUNK_DEBUG printf ("returning incomplete read at 1\n"); printf ("i=%d len=%d\n", i, len); #endif return 0; } else if (yaz_isdigit(buf[i])) chunk_len = chunk_len * 16 + (buf[i++] - '0'); else if (yaz_isupper(buf[i])) chunk_len = chunk_len * 16 + (buf[i++] - ('A'-10)); else if (yaz_islower(buf[i])) chunk_len = chunk_len * 16 + (buf[i++] - ('a'-10)); else break; if (chunk_len == 0) break; if (chunk_len < 0) return i; while (1) { if (i >= len -1) return 0; if (skip_crlf(buf, len, &i)) break; i++; } /* got CRLF */ #if CHUNK_DEBUG printf ("chunk_len=%d\n", chunk_len); #endif i += chunk_len; if (i >= len-2) return 0; if (!skip_crlf(buf, len, &i)) return 0; } /* consider trailing headers .. */ while (i < len) { if (skip_crlf(buf, len, &i)) { if (skip_crlf(buf, len, &i)) return i; } else i++; } #if CHUNK_DEBUG printf ("returning incomplete read at 2\n"); printf ("i=%d len=%d\n", i, len); #endif return 0; }
static int cs_complete_http(const char *buf, int len, int head_only) { /* deal with HTTP request/response */ int i, content_len = 0, chunked = 0; /* need at least one line followed by \n or \r .. */ for (i = 0; ; i++) if (i == len) return 0; /* incomplete */ else if (buf[i] == '\n' || buf[i] == '\r') break; /* check to see if it's a response with content */ if (!head_only && !memcmp(buf, "HTTP/", 5)) { int j; for (j = 5; j < i; j++) if (buf[j] == ' ') { ++j; if (buf[j] == '1') /* 1XX */ ; else if (!memcmp(buf + j, "204", 3)) ; else if (!memcmp(buf + j, "304", 3)) ; else content_len = -1; break; } } #if 0 printf("len = %d\n", len); fwrite (buf, 1, len, stdout); printf("----------\n"); #endif for (i = 2; i <= len-2; ) { if (i > 8192) { return i; /* do not allow more than 8K HTTP header */ } if (skip_crlf(buf, len, &i)) { if (skip_crlf(buf, len, &i)) { /* inside content */ if (chunked) return cs_read_chunk(buf, i, len); else { /* not chunked ; inside body */ if (content_len == -1) return 0; /* no content length */ else if (len >= i + content_len) { return i + content_len; } } break; } else if (i < len - 20 && !yaz_strncasecmp((const char *) buf+i, "Transfer-Encoding:", 18)) { i+=18; while (buf[i] == ' ') i++; if (i < len - 8) if (!yaz_strncasecmp((const char *) buf+i, "chunked", 7)) chunked = 1; } else if (i < len - 17 && !yaz_strncasecmp((const char *)buf+i, "Content-Length:", 15)) { i+= 15; while (buf[i] == ' ') i++; content_len = 0; while (i <= len-4 && yaz_isdigit(buf[i])) content_len = content_len*10 + (buf[i++] - '0'); if (content_len < 0) /* prevent negative offsets */ content_len = 0; } else i++; } else i++; } return 0; }
int main(int argc, char **argv) { int rval = 0; lookfile = init_args(argc, argv); if(lookfile == stdin){ printf(APPTITLE " >:O MUHAHAHA. READY. SET. GO!\n"); printf("LINE NUMBERS BETWEEN %d AND %d!\n",LINENUM_MIN,LINENUM_MAX); printf("\n"); printf(INPUTLINE_START); fflush(stdout); getlook(); for(;;){ skipwhite(); if(look == EOF) break; if(isdigit(look)){ /* BASIC program line */ parse_BASIC_line(); }else if(isalpha(look)){ /* BASIC command */ parse_BASIC_command(); }else{ /* Syntax error */ read_to_eol(); error("syntax error"); } printf(INPUTLINE_START); fflush(stdout); skip_crlf(); } }else{ getlook(); for(;;){ skipwhite(); if(look == EOF) break; if(!isdigit(look)){ error("no line number"); rval = 1; break; } parse_BASIC_line(); skip_crlf(); } if(rval == 0){ command_run(); } fclose(lookfile); } lineset_free(); printf("\n"); return rval; }