/* * Author: Lubomir Host 'rajo' * $Log: http.c,v $ * Revision 1.16 2002/05/09 16:10:49 host8 * * Test of cvs commit (loginfo.sh changed). * * New implementation of HTTP protocol, doesn't work yet. * * Revision 1.15 2001/11/19 20:15:07 host8 * Http protocol probably works fine. * * Revision 1.14 2001/11/16 19:30:01 host8 * Patched bug in declaration/definition of global variable debug. * * Revision 1.13 2001/11/14 16:00:07 host8 * Changed some debug messages. * Improvements in cookies (still not works fine). * * Revision 1.12 2001/11/12 20:19:10 host8 * http_connect() probably works fine. * Some problems with http_requests for www.mtnsms.com. * * Revision 1.11 2001/11/12 16:08:00 host8 * Big improvements in http. connect() doesn't work correctly yet. * * Revision 1.10 2001/10/30 18:18:12 jombik9 * Improvements. * */ #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "mail2sms.h" #include "strings.h" #include "strdyn.h" #include "http.h" static void free_cookie(COOKIE *c); static COOKIE *new_cookie(void); static COOKIE *duplicate_cookie(COOKIE *c); static COOKIE **add_to_cookies(COOKIE **coo, COOKIE *c); static char * get_cookie(HTTP_REQUEST *r); static int get_size_cookies(COOKIE **coo); static void http_set_cookie(char *str); static void free_request(HTTP_REQUEST *r); static int get_size_requests(HTTP_REQUEST **req); static HTTP_REQUEST **create_requests(void); static HTTP_REQUEST *new_request(void); static HTTP_REQUEST *duplicate_request(HTTP_REQUEST *r); static HTTP_REQUEST **add_to_requests(HTTP_REQUEST **req, HTTP_REQUEST *r); static char *get_http_referer(HTTP_REQUEST **req); HTTP_REQUEST **requests; COOKIE **cookies; /* // static struct addrinfo *GetAddrInfo(const char *str, int port) {{{ static struct addrinfo *GetAddrInfo(const char *host, int port) { struct addrinfo hints, *res; int error; memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; error = getaddrinfo(host, "80", &hints, &res); if (error || !res) { fprintf(stderr, "GetAddrInfo: getaddrinfo(%s, %d): %s\n", host, port, strerror(error)); res = NULL; } return res; } // }}} */ // static void free_cookie(COOKIE *c) {{{ static void free_cookie(COOKIE *c) { free(c->domain); free(c->text); free(c); } // }}} // static COOKIE **create_cookies(void) {{{ static COOKIE **create_cookies(void) { register COOKIE **coo; if ((coo = (COOKIE **) malloc(1 * sizeof(COOKIE *))) == NULL) return NULL; coo[0] = NULL; return (coo); } // }}} // static COOKIE *new_cookie(void) {{{ static COOKIE *new_cookie(void) { COOKIE *new; new = (COOKIE *) malloc(1*sizeof(COOKIE)); new->domain = NULL; new->text = NULL; return (new); } // }}} // static COOKIE *duplicate_cookie(COOKIE *c) {{{ static COOKIE *duplicate_cookie(COOKIE *c) { COOKIE *new; if (c == NULL) return (NULL); if ((new = new_cookie()) == NULL) return (NULL); if (c->domain != NULL) new->domain = strdup(c->domain); if (c->text != NULL) new->text = strdup(c->text); return (new); } // }}} // static COOKIE **add_to_cookies(COOKIE **coo, COOKIE *r) {{{ static COOKIE **add_to_cookies(COOKIE **coo, COOKIE *c) { register int count; if (coo == NULL) if ((coo = create_cookies()) == NULL) return NULL; if (c == NULL) return (coo); count = get_size_cookies(coo); coo = (COOKIE **) realloc(coo, (count + 2) * sizeof(COOKIE *)); if (coo == NULL) return NULL; coo[count] = c; coo[count + 1] = NULL; return coo; } // }}} // static COOKIE *parse_cookie(char *str) {{{ static COOKIE *parse_cookie(char *str) { COOKIE *c = NULL; char **array; int i, j; char *tmp; /* Cookies {{{ read(4, "HTTP/1.1 302 Object moved\r\n Server: Microsoft-IIS/5.0\r\n Date: Mon, 22 Oct 2001 16:43:36 GMT\r\n Location: http://www4.mtnsms.com/members/contacts/contacts.asp\r\n Connection: Keep-Alive\r\n Content-Length: 173\r\n Content-Type: text/html\r\n Expires: Mon, 22 Oct 2001 16:43:36 GMT\r\n Set-Cookie: mtnsms%2Ep%2E2=color=0&cn=rajo%40host%2Esk&akey=; expires=Sat, 22-Oct-2011 16:43:36 GMT; domain=.mtnsms.com; path=/\r\n Set-Cookie: mtnsms%2Et%2E2=skey=178A2593%2D5FA7%2D406B%2D8DE9%2D5EA0B8A4BB15; domain=.mtnsms.com; path=/\r\n Cache-control: private\r\n\r\n Accept-Language: en\r\nUser-Agent: Lynx/2.8.4dev.7 libwww-FM/2.14\r\n Referer: http://www.mtnsms.com/\r\n Cookie2: $Version=\"1\"\r\n Cookie: mtnsms%2Ep%2E2=color=0&cn=rajo%40host%2Esk&akey=; mtnsms%2Et%2E2=skey=178A2593%2D5FA7%2D406B%2D8DE9%2D5EA0B8A4BB15\r\n\r\n", 747) = 747 * }}} Cookies */ array = strdyn_explode_chr(str, ';'); /* search for cookies with same domain, * if found, not alloc new cookie. */ for (i=0; array[i] != NULL; i++) { tmp = array[i]; if (tmp == strstr(tmp, " domain=")) { int count; count = get_size_cookies(cookies); for (j=(count-1); j >= 0; j--) { if (cookies[j] != NULL && cookies[j]->domain != NULL && strstr(tmp, cookies[j]->domain) != NULL) { /* same domain found, set c to these */ c = cookies[j]; break; } } } } if (c == NULL) { // domain not found c = new_cookie(); } for (i=0; array[i] != NULL; i++) { #ifdef DEBUG if (debug > 4) fprintf(stderr, "COOKIES: parsed_cookie[%d] = '%s'\n", i, array[i]); #endif tmp = array[i]; if (tmp == strstr(tmp, " domain=")) { c->domain = strdup(tmp+8); } else if (tmp == strstr(tmp, " expires=")) { /* ignored */ } else if (tmp == strstr(tmp, " path=")) { /* ignored */ } else { #ifdef DEBUG if (debug > 4) fprintf(stderr, "COOKIES: cookies->text-old = '%s'\n", c->text); #endif if (c->text == NULL) c->text = strdup(tmp); else { char *ar[3]; ar[0] = c->text, ar[1] = tmp, ar[2] = NULL; c->text = strdyn_implode2_str(ar, "; "); } #ifdef DEBUG if (debug > 4) fprintf(stderr, "COOKIES: cookies->text-new = '%s'\n", c->text); #endif } } #ifdef DEBUG if (debug > 4) fprintf(stderr, "COOKIES: returning cookie, " "c->domain = '%s' c->text ='%s'\n", c->domain, c->text); #endif return (c); } // }}} // static char * get_cookie(HTTP_REQUEST *r) {{{ static char *get_cookie(HTTP_REQUEST *r) { int i; int count; char *str = NULL; if (r == NULL || r->host == NULL) return (NULL); count = get_size_cookies(cookies); for (i=(count-1); i >= 0; i--) { if (cookies[i] != NULL && cookies[i]->domain != NULL && strstr(r->host, cookies[i]->domain) != NULL) { str = cookies[i]->text; break; } } #ifdef DEBUG if (debug > 4) fprintf(stderr, "COOKIES: get_cookie() = '%s'\n", str); #endif return (str); } // }}} // static int get_size_cookies(COOKIE **coo) {{{ static int get_size_cookies(COOKIE **coo) { register int i; for (i = 0; coo[i] != NULL; i++) ; return i; } // }}} // static void http_set_cookie(char *str) {{{ static void http_set_cookie(char *str) { if (str != NULL) { if (str == strstr(str, "Set-Cookie: ")) { #ifdef DEBUG if (debug > 4) fprintf(stderr, "COOKIES: adding cookie '%s'\n", str); #endif cookies = add_to_cookies(cookies, parse_cookie(str + 12)); } } } // }}} // static void free_request(HTTP_REQUEST *r) {{{ static void free_request(HTTP_REQUEST *r) { if (r->ret_val != NULL) free(r->ret_val); if (r->host != NULL) free(r->host); if (r->file != NULL) free(r->file); free(r); } // }}} // static int get_size_requests(HTTP_REQUEST **req) {{{ static int get_size_requests(HTTP_REQUEST **req) { register int i; for (i = 0; req[i] != NULL; i++) ; return i; } // }}} // static HTTP_REQUEST **create_requests(void) {{{ static HTTP_REQUEST **create_requests(void) { register HTTP_REQUEST **req; if ((req = (HTTP_REQUEST **) malloc(1 * sizeof(HTTP_REQUEST *))) == NULL) return NULL; req[0] = NULL; return (req); } // }}} // static HTTP_REQUEST *new_request(void) {{{ static HTTP_REQUEST *new_request(void) { HTTP_REQUEST *new; new = (HTTP_REQUEST *) malloc(1*sizeof(HTTP_REQUEST)); return (new); } // }}} // static HTTP_REQUEST *duplicate_request(HTTP_REQUEST *r) {{{ static HTTP_REQUEST *duplicate_request(HTTP_REQUEST *r) { HTTP_REQUEST *new; if (r == NULL) return (NULL); if ((new = new_request()) == NULL) return (NULL); new->frw = r->frw; new->method = r->method; new->port = r->port; fprintf(stderr, "%d - OK\n", __LINE__); if (r->ret_val != NULL) new->ret_val = strdup(r->ret_val); else new->ret_val = NULL; fprintf(stderr, "%d - OK\n", __LINE__); if (r->host != NULL) new->host = strdup(r->host); else new->host = NULL; fprintf(stderr, "%d - OK\n", __LINE__); if (r->file != NULL) new->file = strdup(r->file); else new->file = NULL; fprintf(stderr, "%d - OK\n", __LINE__); return (new); } // }}} // static HTTP_REQUEST **add_to_requests(HTTP_REQUEST **req, HTTP_REQUEST *r) {{{ static HTTP_REQUEST **add_to_requests(HTTP_REQUEST **req, HTTP_REQUEST *r) { register int count; if (req == NULL) if ((req = create_requests()) == NULL) return NULL; count = get_size_requests(req); req = (HTTP_REQUEST **) realloc(req, (count + 2) * sizeof(HTTP_REQUEST *)); if (req == NULL) return NULL; // req[count] = duplicate_request(r); req[count] = r; req[count + 1] = NULL; return req; } // }}} // static char * get_http_referer(HTTP_REQUEST **req) {{{ static char *get_http_referer(HTTP_REQUEST **req) { int count; count = get_size_requests(req); if (count > 0) { return (req[count - 1]->referer); } return (NULL); } // }}} // static char * http_clean_referer(HTTP_REQUEST **req) {{{ void http_clean_referer(HTTP_REQUEST **req) { int i; for (i=0; req[i] != NULL; i++) { if (req[i]->referer != NULL) free(req[i]->referer); } return ; } // }}} // static http_connect(HTTP_REQUEST *r) {{{ static FILE *http_connect(HTTP_REQUEST *r) { int s = 0; int i, idx = -1; struct sockaddr_in serv_addr; // struct addrinfo *res0; if (r == NULL || r->host == NULL) return (NULL); for (i=0; servers[i].desc != NULL; i++) { if (servers[i].id == id) { idx = i; break; } } if (idx == -1) { fprintf(stderr, "Id %d not found in servers[] !\n", id); exit(1); } memset((char *) &serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = inet_addr(r->host); if (serv_addr.sin_addr.s_addr == INADDR_NONE) { struct hostent *pent = gethostbyname(r->host); if (pent != NULL) serv_addr.sin_addr.s_addr = *((u_long *) (pent->h_addr)); } if (serv_addr.sin_addr.s_addr == INADDR_NONE) { #ifdef DEBUG if (debug > 8) { fprintf(stderr, "%s: %d - catched error\n", __FILE__, __LINE__); } #endif fprintf(stderr, "Can't connect to %s[%s:%hd] - %s\n", servers[idx].desc, servers[idx].ip, r->port, strerror(errno)); return (NULL); } if (r->port != 0) { serv_addr.sin_port = htons((u_short) r->port); if (serv_addr.sin_port == 0) { struct servent *pent; char str_port[10]; #ifdef DEBUG if (debug > 6) { fprintf(stderr, "(u_short) r->port = %hd\n", r->port); } #endif if (snprintf(str_port, 9, "%hd", r->port) == -1) { fprintf(stderr, "Can't connect to %s[%s:%s] - %s\n", servers[idx].desc, servers[idx].ip, str_port, strerror(errno)); return (NULL); } pent = getservbyname(str_port, "tcp"); if (pent != NULL) serv_addr.sin_port = pent->s_port; } if (serv_addr.sin_port == 0) { #ifdef DEBUG if (debug > 8) { fprintf(stderr, "%s: %d - catched error\n", __FILE__, __LINE__); } #endif fprintf(stderr, "Can't connect to %s[%s:%hd] - %s\n", servers[idx].desc, servers[idx].ip, r->port, strerror(errno)); return (NULL); } } else { // No port specified ... use telnet port. // struct servent *pent; pent = getservbyname ("www", "tcp"); if (pent == NULL) serv_addr.sin_port = htons(80); else serv_addr.sin_port = pent->s_port; } s = socket(PF_INET, SOCK_STREAM, 0); if (s != -1) { for (i=0; ifrw = fdopen(s, "w+b")) != NULL) return (r->frw); } } } else { #ifdef DEBUG if (debug > 8) { fprintf(stderr, "%s: %d - catched error\n", __FILE__, __LINE__); } #endif fprintf(stderr, "Can't connect to %s[%s:%hd] - %s\n", servers[idx].desc, servers[idx].ip, r->port, strerror(errno)); return (NULL); } #ifdef DEBUG if (debug > 8) { fprintf(stderr, "%s: %d - catched error\n", __FILE__, __LINE__); } #endif fprintf(stderr, "Can't connect to %s[%s:%hd] - %s\n", servers[idx].desc, servers[idx].ip, r->port, strerror(errno)); return (NULL); } // }}} // static void http_read_source(HTTP_REQUEST *r) {{{ static void http_read_source(HTTP_REQUEST *r) { int search_for_link = 0; #ifdef DEBUG int info = debug; #else int info = 1; #endif int bad_request = 0; char *buf; char *new_host = NULL; char *new_file = NULL; #define BUF_SIZE 1024 if ((buf = (char *) malloc((BUF_SIZE)*sizeof(char))) == NULL) { fprintf(stderr, "Memory aloocation failed!\n"); exit(1); } while (1) { memset(buf, 0, BUF_SIZE); if (fgets(buf, ((BUF_SIZE) -1), r->frw) == NULL) break; buf[BUF_SIZE -1] = '\0'; strrmeol(buf); if (r->ret_val == NULL) r->ret_val = strdup(buf); if (buf == strstr(buf, "Set-Cookie: ")) http_set_cookie(buf); if (search_for_link == 1) { /* Handling " 302 Object Moved" {{{ */ if (buf == strstr(buf, "Location: ")) { char *str; char *tmp; if ((str = strdup(buf)) == NULL) { fprintf(stderr, "strdup(%s) failed!\n", buf); exit(1); } strrmeol(str); if ((tmp = strstr((str + 17), "/")) != NULL) { new_file = strdup(tmp); new_host = (char *) malloc ((tmp - str - 16)*sizeof(char)); strncpy(new_host, (str + 17), (tmp - str - 17)); new_host[tmp - str - 17] = '\0'; #ifdef DEBUG fprintf(stderr, "FILENAME = '%s', HOST = '%s'\n", new_file, new_host); #endif } #ifdef DEBUG else { fprintf(stderr, "Invalid link '%s'!\n", str); } fprintf(stderr, "Object Moved = '%s'\n", str); #endif free(str); search_for_link = 0; } } /* }}} End of Handling '302 Object Moved' */ if (info) { fprintf(stderr, "\t%.*s\n", (int)(strlen(buf)), buf); info=0; if (strstr(buf, "HTTP/1.") != NULL) { if ((buf+8) == strstr(buf, " 200 OK")) { // TODO: test this: r->referer = strdup(r->host); //http_set_referer(host, file); } if ((buf+8) == strstr(buf, " 302 Object moved")) { #ifdef DEBUG fprintf(stderr, "Searching for 'Location: '...\n"); #endif search_for_link = 1 ; } if ((buf+8) == strstr(buf, " 400 Bad Request")) { bad_request = 1; } if ((buf+8) == strstr(buf, " 404 Object Not Found")) { bad_request = 1; } if ((buf+8) == strstr(buf, " 500 Server Error")) { bad_request = 1; } } } #ifdef DEBUG if (debug > 10) { fprintf(stderr, "HTTP_SOURCE: '%s'\n", buf); } else if (debug > 8 ) { fputs(buf, stderr); } #endif } #ifdef DEBUG if (search_for_link == 1) { fprintf(stderr, "Link NOT FOUND!\n"); } #endif fclose (r->frw); if (bad_request) exit(1); if (new_host != NULL && new_file != NULL) { http_request(HTTP_GET, new_file, new_host, NULL); free(new_host); free(new_file); } free(buf); } // }}} // int http_request_by_request(HTTP_REQUEST *r) {{{ int http_request_by_request(HTTP_REQUEST *r) { return (http_request(r->method, r->file, r->host, NULL)); } // }}} // int http_request(int method, char *file, char *host, char *fmt, ...) {{{ int http_request(int method, char *file, char *host, char *fmt, ...) { va_list ap; HTTP_REQUEST *r; #ifdef DEBUG if (debug) { // Debug code STAHUJEM/POSIELAM {{{ if (method == HTTP_GET) { fprintf(stderr, "GET: %s%s\n", host, file); } else if (method == HTTP_POST) { fprintf(stderr, "POST: %s%s\n", host, file); } } // }}} #endif r = new_request(); r->port = (u_short) 80; r->method = method; r->host = strdup(host); r->file = strdup(file); requests = add_to_requests(requests, r); if ((r->frw = http_connect(r)) == NULL) { exit(errno); } switch (r->method) { case HTTP_GET: fprintf(r->frw, "GET %s HTTP/1.0\r\n", file); break; case HTTP_POST: fprintf(r->frw, "POST %s HTTP/1.0\r\n", file); break; default: fprintf(stderr, "Unknown http method %d\n", method); break; } fprintf(r->frw, "Host: %s\r\n", host); fprintf(r->frw, "Accept: text/html, text/plain, application/applefile, "); fprintf(r->frw, "application/x-metamail-patch, sun-deskset-message, "); fprintf(r->frw, "mail-file, default, postscript-file, audio-file, "); fprintf(r->frw, "x-sun-attachment, text/enriched, text/richtext, "); fprintf(r->frw, "application/andrew-inset, x-be2\r\n"); fprintf(r->frw, "Accept: application/postscript, message/external-body, "); fprintf(r->frw, "message/partial, image/g3fax, application/pdf, "); fprintf(r->frw, "application/pgp, application/pgp, video/mpeg, video/*, "); fprintf(r->frw, "image/*, audio/mod, text/sgml, */*;q=0.01\r\n"); fprintf(r->frw, "Accept-Encoding: gzip, compress\r\n"); fprintf(r->frw, "Accept-Language: en\r\n"); if (method == HTTP_POST) { fprintf(r->frw, "Pragma: no-cache\r\n"); fprintf(r->frw, "Cache-Control: no-cache\r\n"); } fprintf(r->frw, "%s", USER_AGENT); if (get_http_referer(requests) != NULL) fprintf(r->frw, "Referer: %s\r\n", get_http_referer(requests)); if (get_cookie(r) != NULL) { #ifdef DEBUG if (debug > 4) fprintf(stderr, "HTTP: sending cookies:\r\n" "Cookie2: $Version=\"1\"\r\n" "Cookie: %s\r\n", get_cookie(r)); #endif fprintf(r->frw, "Cookie2: $Version=\"1\"\r\nCookie: %s\r\n", get_cookie(r)); } if (fmt != NULL) { va_start(ap, fmt); vfprintf(r->frw, fmt, ap); va_end(ap); } fprintf(r->frw, "\r\n"); http_read_source(r); #ifdef DEBUG if (debug) { fprintf(stderr, "HTTP request sent, reply OK...\n"); } #endif return 0; } // }}} // char *get_last_hostname(void) {{{ char *get_last_hostname(void) { int count; count = get_size_requests(requests); #ifdef DEBUG if (debug > 6) { fprintf(stderr, "get_last_hostname() = '%s'\n", requests[count-1]->host); } #endif return (requests[count-1]->host); } // }}} // void http_init(void) {{{ void http_init(void) { if ((requests = create_requests()) == NULL) { fprintf(stderr, "Failed creation of internal structures!\n"); exit(1); } if ((cookies = create_cookies()) == NULL) { fprintf(stderr, "Failed creation of internal structures!\n"); exit(1); } return; } // }}} // void free_requests(HTTP_REQUEST **req) {{{ void free_requests(HTTP_REQUEST **req) { register int i; for (i = 0; req[i] != NULL; i++) free_request(req[i]); free(req); } // }}} /* Modeline for ViM {{{1 * vim:set ts=4: * vim600:fdm=marker fdl=0 fdc=3: * }}}1 */