Connect to winehq.org by its name rather than by its IP addr.
[wine] / programs / winetest / send.c
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  *
19  */
20 #include <winsock.h>
21 #include <stdio.h>
22 #include <errno.h>
23
24 #include "winetest.h"
25
26 SOCKET
27 open_http (const char *server)
28 {
29     WSADATA wsad;
30     struct sockaddr_in sa;
31     SOCKET s;
32
33     report (R_STATUS, "Opening HTTP connection to %s", server);
34     if (WSAStartup (MAKEWORD (2,2), &wsad)) return INVALID_SOCKET;
35
36     s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
37     if (s != INVALID_SOCKET) {
38         unsigned long addr = inet_addr(server);
39
40         sa.sin_family = AF_INET;
41         sa.sin_port = htons (80);
42         if (addr != INADDR_NONE)
43             sa.sin_addr.s_addr = addr;
44         else
45         {
46             struct hostent *host;
47
48             if ((host = gethostbyname(server)) != NULL)
49                 addr = ((struct in_addr *)host->h_addr)->s_addr;
50         }
51         if (!connect (s, (struct sockaddr*)&sa,
52                       sizeof (struct sockaddr_in)))
53             return s;
54     }
55     WSACleanup ();
56     return INVALID_SOCKET;
57 }
58
59 int
60 close_http (SOCKET s)
61 {
62     int ret;
63
64     ret = closesocket (s);
65     return (WSACleanup () || ret);
66 }
67
68 int
69 send_buf (SOCKET s, const char *buf, size_t length)
70 {
71     int sent;
72
73     while (length > 0) {
74         sent = send (s, buf, length, 0);
75         if (sent == SOCKET_ERROR) return 1;
76         buf += sent;
77         length -= sent;
78     }
79     return 0;
80 }
81
82 int
83 send_str (SOCKET s, ...)
84 {
85     va_list ap;
86     char *p;
87     int ret;
88     size_t len;
89
90     va_start (ap, s);
91     p = vstrmake (&len, ap);
92     va_end (ap);
93     if (!p) return 1;
94     ret = send_buf (s, p, len);
95     free (p);
96     return ret;
97 }
98
99 int
100 send_file (const char *name)
101 {
102     SOCKET s;
103     FILE *f;
104 #define BUFLEN 8192
105     unsigned char *buffer;
106     size_t bytes_read, total, filesize;
107     char *str;
108     int ret;
109
110     /* RFC 2068 */
111 #define SEP "-"
112     const char head[] = "POST /submit HTTP/1.0\r\n"
113         "Host: afavant\r\n"
114         "User-Agent: Winetests Shell\r\n"
115         "Content-Type: multipart/form-data; boundary=" SEP "\r\n"
116         "Content-Length: %u\r\n\r\n";
117     const char body1[] = "--" SEP "\r\n"
118         "Content-Disposition: form-data; name=reportfile; filename=\"%s\"\r\n"
119         "Content-Type: application/octet-stream\r\n\r\n";
120     const char body2[] = "\r\n--" SEP "\r\n"
121         "Content-Dispoition: form-data; name=submit\r\n\r\n"
122         "Upload File\r\n"
123         "--" SEP "--\r\n";
124
125     buffer = xmalloc (BUFLEN + 1);
126     s = open_http ("www.winehq.org");
127     if (s == INVALID_SOCKET) {
128         report (R_WARNING, "Can't open network connection: %d",
129                 WSAGetLastError ());
130         return 1;
131     }
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 > 1024*1024) {
141         report (R_WARNING,
142                 "File too big (%d > 1 MB), copy and submit manually",
143                 filesize);
144         goto abort2;
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     while ((bytes_read = fread (buffer, 1, BUFLEN / 8, f))) {
162         if (send_buf (s, buffer, bytes_read)) {
163             report (R_WARNING, "Error sending body: %d, %d",
164                     errno, WSAGetLastError ());
165             goto abort2;
166         }
167         report (R_DELTA, bytes_read, "Network transfer: In progress");
168     }
169     fclose (f);
170
171     if (send_buf (s, body2, sizeof body2 - 1)) {
172         report (R_WARNING, "Error sending trailer: %d, %d",
173                 errno, WSAGetLastError ());
174         goto abort2;
175     }
176     report (R_DELTA, 0, "Network transfer: Done");
177
178     total = 0;
179     while ((bytes_read = recv (s, buffer+total, BUFLEN-total, 0))) {
180         if ((signed)bytes_read == SOCKET_ERROR) {
181             report (R_WARNING, "Error receiving reply: %d, %d",
182                     errno, WSAGetLastError ());
183             goto abort1;
184         }
185         total += bytes_read;
186         if (total == BUFLEN) {
187             report (R_WARNING, "Buffer overflow");
188             goto abort1;
189         }
190     }
191     if (close_http (s)) {
192         report (R_WARNING, "Error closing connection: %d, %d",
193                 errno, WSAGetLastError ());
194         return 1;
195     }
196
197     str = strmake (&bytes_read, "Received %s (%d bytes).\n",
198                    name, filesize);
199     ret = memcmp (str, buffer + total - bytes_read, bytes_read);
200     free (str);
201     if (ret) {
202         buffer[total] = 0;
203         str = strstr (buffer, "\r\n\r\n");
204         if (str) buffer = str + 4;
205         report (R_ERROR, "Can't submit logfile '%s'. "
206                 "Server response: %s", name, buffer);
207     }
208     free (buffer);
209     return ret;
210
211  abort2:
212     fclose (f);
213  abort1:
214     close_http (s);
215     free (buffer);
216     return 1;
217 }