// Http.cpp // 2013/11/20 #include #include #include #include #include #include #include #include #include #include #include #include "Http.h" //#define VERBOSE namespace portable { /* * read a line from file descriptor * returns the number of bytes read. negative if a read error occured * before the end of line or the max. * cariage returns (CR) are ignored. */ int Http::http_read_line (int fd,char *buffer,int max) { /* not efficient on long lines (multiple unbuffered 1 char reads) */ int n=0; while (nh_addr, hp->h_length); server.sin_family = hp->h_addrtype; server.sin_port = htons( http_proxy_server.size() ? u_short(http_proxy_port):u_short(http_port) ); int s = (int) socket(AF_INET, SOCK_STREAM, 0); if(s < 0) { ret = ERRSOCK; return IsGood(); } setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, 0, 0); if (connect(s, (const sockaddr*) &server, sizeof(server)) < 0) { ret=ERRCONN; return IsGood(); } if(pfd) { *pfd=s; } if (http_proxy_server.size()) { sprintf(header, "%s http://%.128s:%d/%.256s HTTP/1.1\r\n" "Host: %s:%i\r\n" "Connection: close\r\n" "User-Agent: %s\r\n" "%s\r\n\r\n", command,http_server.c_str(), http_port, url, http_server.c_str(),http_port, http_user_agent, additional_header); } else { sprintf(header, "%s %.256s HTTP/1.1\r\n" "Host: %s:%i\r\n" "Connection: close\r\n" "User-Agent: %s\r\n" "%s\r\n\r\n", command,url, http_server.c_str(), http_port, http_user_agent, additional_header); } hlg=(int)strlen(header); if(write(s,header,hlg)!=hlg) { ret=ERRWRHD; close(s); return IsGood(); } if(length && data && (write(s,data,length)!=length) ) { ret=ERRWRDT; close(s); return IsGood(); } const int bytes = http_read_line(s,header,MAXBUF-1); #ifdef VERBOSE fputs(header,stderr); putc('\n',stderr); #endif if(bytes<=0) { ret=ERRRDHD; close(s); return IsGood(); } if(sscanf(header,"HTTP/1.%*d %03d",(int*)&ret)!=1) { ret=ERRPAHD; close(s); return IsGood(); } if(mode==KEEP_OPEN) { return IsGood(); } close(s); return IsGood(); } /* * Put data on the server * * This function sends data to the http data server. * The data will be stored under the ressource name filename. * returns a negative error code or a positive code from the server * * limitations: filename is truncated to first 256 characters * and type to 64. */ bool Http::http_put(char *data,int length,int overwrite,char *type) { char header[MAXBUF]; if (type) sprintf(header,"Content-length: %d\015\012Content-type: %.64s\015\012%s", length, type , overwrite ? "Control: overwrite=1\015\012" : "" ); else sprintf(header,"Content-length: %d\015\012%s",length, overwrite ? "Control: overwrite=1\015\012" : "" ); return http_query("PUT",filename.c_str(),header,CLOSE, data, length, NULL); } #pragma warning(default : 4996) /* * Get data from the server * * This function gets data from the http data server. * The data is read from the ressource named filename. * Address of new new allocated memory block is filled in pdata * whose length is returned via plength. * * returns a negative error code or a positive code from the server * * * limitations: filename is truncated to first 256 characters */ #pragma warning(disable : 4996) bool Http::http_get(char *pdata,int *plength,char *typebuf) { char header[MAXBUF]; char *pc; int fd; int n,length=-1; if (!pdata) { ret = ERRNULL; return IsGood(); } *pdata=0; if (typebuf) { *typebuf='\0'; } http_query("GET",filename.c_str(),"",KEEP_OPEN, NULL, 0, &fd); if(ret!=200) { if (ret>=0) { close(fd); } return IsGood(); } for(;;) { n=http_read_line(fd,header,MAXBUF-1); #ifdef VERBOSE fputs(header,stderr); putc('\n',stderr); #endif if (n<=0) { close(fd); ret = ERRRDHD; return IsGood(); } /* empty line ? (=> end of header) */ if ( n>0 && (*header)=='\0') { break; } length+=n; /* try to parse some keywords : */ /* convert to lower case 'till a : is found or end of String */ for (pc=header; (*pc!=':' && *pc) ; pc++) { *pc=char(tolower(*pc)); } // sscanf(header,"content-length: %d",&length); if (typebuf) { sscanf(header,"content-type: %s",typebuf); } } if (length<=0) { close(fd); ret = ERRNOLG; return IsGood(); } if(*plength end of header) */ if ( n>0 && (*header)=='\0') break; /* try to parse some keywords : */ /* convert to lower case 'till a : is found or end of String */ for (pc=header; (*pc!=':' && *pc) ; pc++) *pc=char(tolower(*pc)); sscanf(header,"content-length: %d",&length); if (typebuf) sscanf(header,"content-type: %s",typebuf); } if (plength) *plength=length; close(fd); } else if (ret>=0) close(fd); return IsGood(); } /* * Delete data on the server * * This function request a DELETE on the http data server. * * returns a negative error code or a positive code from the server * * limitations: filename is truncated to first 256 characters */ bool Http::http_delete() { return http_query("DELETE",filename.c_str(),"",CLOSE, NULL, 0, NULL); } /* parses an url : setting the http_server and http_port global variables * and returning the filename to pass to http_get/put/... * returns a negative error code or 0 if sucessfully parsed. */ bool Http::http_parse_url(const char *url) { if (strncasecmp("http://",url,7)) { #ifdef VERBOSE fprintf(stderr,"invalid url (must start with 'http://')\n"); #endif ret = ERRURLH; return IsGood(); } // http://server:port/ url+=7; http_server.erase(); filename.erase(); http_port=80; const char* domain=url; char* endOf=const_cast(strchr(domain,':')); if(endOf) { http_server=String(domain,endOf-domain); endOf++; if (sscanf(endOf,"%d",&http_port)!=1) { #ifdef VERBOSE fprintf(stderr,"invalid port in url\n"); #endif ret = ERRURLP; return IsGood(); } } endOf= const_cast(strchr(domain,'/')); if(!http_server.size()) { if(endOf) { http_server=String(domain,endOf-domain); } else { http_server=String(domain); ret = OK0; return IsGood(); } } filename=String(endOf); #ifdef VERBOSE fprintf(stderr,"host=%s, port=%d, filename=%s\n", http_server.c_str(),http_port,filename.c_str()); #endif ret = OK0; return IsGood(); } int Http::read(int s,char*buf,int len) { #ifdef WIN32 int size=recv(s,buf,len,0); #if 0 if(size==SOCKET_ERROR) { const int err=WSAGetLastError(); } #endif if(size==16384) { size+=recv(s,buf+16384,len,0); } // cout<<"Read bytes: "<