1 /* 2 * HTTP handling functions. 3 * 4 * Copyright 2003 Ferenc Wagner 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include <winsock.h> 22 #include <stdio.h> 23 #include <errno.h> 24 25 #include "winetest.h" 26 27 static SOCKET 28 open_http (const char *server) 29 { 30 WSADATA wsad; 31 struct sockaddr_in sa; 32 SOCKET s; 33 34 report (R_STATUS, "Opening HTTP connection to %s", server); 35 if (WSAStartup (MAKEWORD (2,2), &wsad)) return INVALID_SOCKET; 36 37 sa.sin_family = AF_INET; 38 sa.sin_port = htons (80); 39 sa.sin_addr.s_addr = inet_addr (server); 40 if (sa.sin_addr.s_addr == INADDR_NONE) { 41 struct hostent *host = gethostbyname (server); 42 if (!host) { 43 report (R_ERROR, "Hostname lookup failed for %s", server); 44 goto failure; 45 } 46 sa.sin_addr.s_addr = ((struct in_addr *)host->h_addr)->s_addr; 47 } 48 s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); 49 if (s == INVALID_SOCKET) { 50 report (R_ERROR, "Can't open network socket: %d", 51 WSAGetLastError ()); 52 goto failure; 53 } 54 if (!connect (s, (struct sockaddr*)&sa, sizeof (struct sockaddr_in))) 55 return s; 56 57 report (R_ERROR, "Can't connect: %d", WSAGetLastError ()); 58 closesocket (s); 59 failure: 60 WSACleanup (); 61 return INVALID_SOCKET; 62 } 63 64 static int 65 close_http (SOCKET s) 66 { 67 int ret; 68 69 ret = closesocket (s); 70 return (WSACleanup () || ret); 71 } 72 73 static int 74 send_buf (SOCKET s, const char *buf, size_t length) 75 { 76 int sent; 77 78 while (length > 0) { 79 sent = send (s, buf, length, 0); 80 if (sent == SOCKET_ERROR) return 1; 81 buf += sent; 82 length -= sent; 83 } 84 return 0; 85 } 86 87 static int 88 send_str (SOCKET s, ...) 89 { 90 va_list ap; 91 char *p; 92 int ret; 93 size_t len; 94 95 va_start (ap, s); 96 p = vstrmake (&len, ap); 97 va_end (ap); 98 if (!p) return 1; 99 ret = send_buf (s, p, len); 100 free (p); 101 return ret; 102 } 103 104 int 105 send_file (const char *name) 106 { 107 SOCKET s; 108 FILE *f; 109 #define BUFLEN 8192 110 char buffer[BUFLEN+1]; 111 size_t bytes_read, total, filesize; 112 char *str; 113 int ret; 114 115 /* RFC 2616 */ 116 #define SEP "--8<--cut-here--8<--" 117 static const char head[] = "POST /submit HTTP/1.0\r\n" 118 "Host: test.winehq.org\r\n" 119 "User-Agent: Winetest Shell\r\n" 120 "Content-Type: multipart/form-data; boundary=\"" SEP "\"\r\n" 121 "Content-Length: %u\r\n\r\n"; 122 static const char body1[] = "--" SEP "\r\n" 123 "Content-Disposition: form-data; name=\"reportfile\"; filename=\"%s\"\r\n" 124 "Content-Type: application/octet-stream\r\n\r\n"; 125 static const char body2[] = "\r\n--" SEP "\r\n" 126 "Content-Disposition: form-data; name=\"submit\"\r\n\r\n" 127 "Upload File\r\n" 128 "--" SEP "--\r\n"; 129 130 s = open_http ("test.winehq.org"); 131 if (s == INVALID_SOCKET) return 1; 132 133 f = fopen (name, "rb"); 134 if (!f) { 135 report (R_WARNING, "Can't open file '%s': %d", name, errno); 136 goto abort1; 137 } 138 fseek (f, 0, SEEK_END); 139 filesize = ftell (f); 140 if (filesize > 1.5*1024*1024) { 141 report (R_WARNING, 142 "File too big (%.1f MB > 1.5 MB); submitting partial report.", 143 filesize/1024.0/1024); 144 filesize = 1.5*1024*1024; 145 } 146 fseek (f, 0, SEEK_SET); 147 148 report (R_STATUS, "Sending header"); 149 str = strmake (&total, body1, name); 150 ret = send_str (s, head, filesize + total + sizeof body2 - 1) || 151 send_buf (s, str, total); 152 free (str); 153 if (ret) { 154 report (R_WARNING, "Error sending header: %d, %d", 155 errno, WSAGetLastError ()); 156 goto abort2; 157 } 158 159 report (R_STATUS, "Sending %u bytes of data", filesize); 160 report (R_PROGRESS, 2, filesize); 161 total = 0; 162 while (total < filesize && (bytes_read = fread (buffer, 1, BUFLEN/2, f))) { 163 if ((signed)bytes_read == -1) { 164 report (R_WARNING, "Error reading log file: %d", errno); 165 goto abort2; 166 } 167 total += bytes_read; 168 if (total > filesize) bytes_read -= total - filesize; 169 if (send_buf (s, buffer, bytes_read)) { 170 report (R_WARNING, "Error sending body: %d, %d", 171 errno, WSAGetLastError ()); 172 goto abort2; 173 } 174 report (R_DELTA, bytes_read, "Network transfer: In progress"); 175 } 176 fclose (f); 177 178 if (send_buf (s, body2, sizeof body2 - 1)) { 179 report (R_WARNING, "Error sending trailer: %d, %d", 180 errno, WSAGetLastError ()); 181 goto abort1; 182 } 183 report (R_DELTA, 0, "Network transfer: Done"); 184 185 total = 0; 186 while ((bytes_read = recv (s, buffer+total, BUFLEN-total, 0))) { 187 if ((signed)bytes_read == SOCKET_ERROR) { 188 report (R_WARNING, "Error receiving reply: %d, %d", 189 errno, WSAGetLastError ()); 190 goto abort1; 191 } 192 total += bytes_read; 193 if (total == BUFLEN) { 194 report (R_WARNING, "Buffer overflow"); 195 goto abort1; 196 } 197 } 198 if (close_http (s)) { 199 report (R_WARNING, "Error closing connection: %d, %d", 200 errno, WSAGetLastError ()); 201 return 1; 202 } 203 204 str = strmake (&bytes_read, "Received %s (%d bytes).\n", 205 name, filesize); 206 ret = memcmp (str, buffer + total - bytes_read, bytes_read); 207 free (str); 208 if (ret) { 209 buffer[total] = 0; 210 str = strstr (buffer, "\r\n\r\n"); 211 if (!str) str = buffer; 212 else str = str + 4; 213 report (R_ERROR, "Can't submit logfile '%s'. " 214 "Server response: %s", name, str); 215 } 216 return ret; 217 218 abort2: 219 fclose (f); 220 abort1: 221 close_http (s); 222 return 1; 223 } 224