#include #include #include #include #include #include #include "http.h" #include "memory.h" #include "util.h" static void free_list(char **list,int nitems){ for(int i=0;i=0: length of string static int sock_get_line(char **dst,int sock){ int linesz=128,linelen=0; char *line=malloc(linesz,char); bool haveCR=false,alsoCR=false; while(true){ char c; ssize_t ret=recv(sock,&c,1,0); if(ret<=0){ free(line); *dst=NULL; return ret-1; } if(c=='\r'){ haveCR=true; continue; } else if(c=='\n'){ break; } else if(haveCR){ haveCR=false; alsoCR=true; } if(linelen+1+alsoCR==linesz){ linesz*=2; if(linesz==0){ exit(255); // Integer overflow! } line=realloc(line,linesz,char); } if(alsoCR){ line[linelen++]='\r'; alsoCR=false; } line[linelen++]=c; } line[linelen]='\0'; *dst=line; return linelen; } // Returns number of lines, or -1 if error static int get_header_lines(char ***dst,int sock){ int arrsz=16,arrlen=0; char **arr=malloc(arrsz,char*); while(true){ char *line; int linelen=sock_get_line(&line,sock); if(linelen<0){ free_list(arr,arrlen); *dst=NULL; return -1; } if(linelen==0){ break; } if(arrlen+1==arrsz){ arrsz*=2; if(arrsz==0){ exit(255); // Integer overflow! } arr=realloc(arr,arrsz,char*); } arr[arrlen++]=line; } arr[arrlen]=NULL; *dst=arr; return arrlen; } static Headers* alloc_headers(void){ Headers *headers=malloc(1,Headers); headers->method=NULL; headers->url=NULL; headers->version=NULL; headers->nheaders=0; headers->headers=NULL; return headers; } void free_headers(Headers *headers){ if(headers==NULL){ return; } if(headers->method)free(headers->method); if(headers->url)free(headers->url); if(headers->version)free(headers->version); if(headers->headers){ for(int i=0;inheaders;i++){ free(headers->headers[i][0]); free(headers->headers[i][1]); } free(headers->headers); } free(headers); } Headers* http_get_headers(int sock){ char **lines; int nlines=get_header_lines(&lines,sock); if(nlines<0){ return NULL; } if(nlines==0){ free_list(lines,nlines); return NULL; } char *spacep=strchr(lines[0],' '); char *space2p=strrchr(lines[0],' '); if(spacep==NULL||space2p==NULL){ free_list(lines,nlines); return NULL; } char *urlstart=spacep+1; while(isspace(*urlstart)){ urlstart++; } if(urlstart>space2p){ // No url? free_list(lines,nlines); return NULL; } Headers *headers=alloc_headers(); headers->method=copy_buf(lines[0],spacep-lines[0]); str_toupper(headers->method); headers->url=copy_buf(urlstart,space2p-urlstart); headers->version=copy_str(space2p); str_toupper(headers->version); int hsz=16; headers->nheaders=0; headers->headers=malloc(hsz,Header); for(int i=1;inheaders+1==hsz){ hsz*=2; // Don't need to check overflow, because nlines would have // overflowed already headers->headers=realloc(headers->headers,hsz,Header); } headers->headers[headers->nheaders][0]=copy_buf(lines[i],colonp-lines[i]); headers->headers[headers->nheaders][1]=copy_str(valuep); headers->nheaders++; } headers->headers[headers->nheaders][0]=NULL; headers->headers[headers->nheaders][1]=NULL; free_list(lines,nlines); return headers; }