Mercurial > pidgin
annotate src/protocols/msn/httpmethod.c @ 7834:99ffabc6ce73
[gaim-migrate @ 8487]
This patch from Mike Hearn should fix HTTP proxy support for MSN, and
provides another step toward the MSN HTTP access method working. The HTTP
proxy may need testing from other people, but looks like it shouldn't give
any problems.
committer: Tailor Script <tailor@pidgin.im>
| author | Christian Hammond <chipx86@chipx86.com> |
|---|---|
| date | Fri, 12 Dec 2003 00:14:40 +0000 |
| parents | 414c701ef1ff |
| children | aa44049e8891 |
| rev | line source |
|---|---|
| 7288 | 1 /** |
| 2 * @file httpmethod.c HTTP connection method | |
| 3 * | |
| 4 * gaim | |
| 5 * | |
| 6 * Copyright (C) 2003 Christian Hammond <chipx86@gnupdate.org> | |
| 7 * | |
| 8 * This program is free software; you can redistribute it and/or modify | |
| 9 * it under the terms of the GNU General Public License as published by | |
| 10 * the Free Software Foundation; either version 2 of the License, or | |
| 11 * (at your option) any later version. | |
| 12 * | |
| 13 * This program is distributed in the hope that it will be useful, | |
| 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 16 * GNU General Public License for more details. | |
| 17 * | |
| 18 * You should have received a copy of the GNU General Public License | |
| 19 * along with this program; if not, write to the Free Software | |
| 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| 21 */ | |
| 22 #include "debug.h" | |
| 23 #include "httpmethod.h" | |
| 24 | |
| 25 #define GET_NEXT(tmp) \ | |
| 26 while (*(tmp) && *(tmp) != ' ' && *(tmp) != '\r') \ | |
| 27 (tmp)++; \ | |
| 28 if (*(tmp) != '\0') *(tmp)++ = '\0'; \ | |
| 29 if (*(tmp) == '\n') (tmp)++; \ | |
| 30 while (*(tmp) && *(tmp) == ' ') \ | |
| 31 (tmp)++ | |
| 32 | |
| 33 #define GET_NEXT_LINE(tmp) \ | |
| 34 while (*(tmp) && *(tmp) != '\r') \ | |
| 35 (tmp)++; \ | |
| 36 if (*(tmp) != '\0') *(tmp)++ = '\0'; \ | |
| 37 if (*(tmp) == '\n') (tmp)++ | |
| 38 | |
| 39 typedef struct | |
| 40 { | |
| 41 MsnServConn *servconn; | |
| 42 char *buffer; | |
| 43 size_t size; | |
| 44 const char *server_type; | |
| 45 | |
| 46 } MsnHttpQueueData; | |
| 47 | |
| 48 static gboolean | |
| 49 http_poll(gpointer data) | |
| 50 { | |
| 51 MsnServConn *servconn = data; | |
| 52 | |
|
7834
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
53 #if 0 |
| 7288 | 54 gaim_debug_info("msn", "Polling server %s.\n", |
| 55 servconn->http_data->gateway_ip); | |
|
7834
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
56 #endif |
| 7288 | 57 msn_http_servconn_poll(servconn); |
| 58 | |
| 59 servconn->http_data->timer = 0; | |
| 60 | |
| 61 return FALSE; | |
| 62 } | |
| 63 | |
| 64 static void | |
| 65 stop_timer(MsnServConn *servconn) | |
| 66 { | |
| 67 if (servconn->http_data->timer) | |
| 68 { | |
| 69 g_source_remove(servconn->http_data->timer); | |
| 70 servconn->http_data->timer = 0; | |
| 71 } | |
| 72 } | |
| 73 | |
| 74 static void | |
| 75 start_timer(MsnServConn *servconn) | |
| 76 { | |
| 77 stop_timer(servconn); | |
| 78 | |
| 79 servconn->http_data->timer = g_timeout_add(5000, http_poll, servconn); | |
| 80 } | |
| 81 | |
| 82 size_t | |
| 83 msn_http_servconn_write(MsnServConn *servconn, const char *buf, size_t size, | |
| 84 const char *server_type) | |
| 85 { | |
|
7834
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
86 size_t s, needed; |
| 7288 | 87 char *params; |
| 88 char *temp; | |
| 89 gboolean first; | |
|
7834
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
90 int res; /* result of the write operation */ |
| 7288 | 91 |
| 92 g_return_val_if_fail(servconn != NULL, 0); | |
| 93 g_return_val_if_fail(buf != NULL, 0); | |
| 94 g_return_val_if_fail(size > 0, 0); | |
| 95 g_return_val_if_fail(servconn->http_data != NULL, 0); | |
| 96 | |
| 97 if (servconn->http_data->waiting_response || | |
| 98 servconn->http_data->queue != NULL) | |
| 99 { | |
| 100 MsnHttpQueueData *queue_data = g_new0(MsnHttpQueueData, 1); | |
| 101 | |
| 102 queue_data->servconn = servconn; | |
| 103 queue_data->buffer = g_strdup(buf); | |
| 104 queue_data->size = size; | |
| 105 queue_data->server_type = server_type; | |
| 106 | |
| 107 servconn->http_data->queue = | |
| 108 g_list_append(servconn->http_data->queue, queue_data); | |
| 109 | |
| 110 return size; | |
| 111 } | |
| 112 | |
| 113 first = servconn->http_data->virgin; | |
| 114 | |
| 115 if (first) | |
| 116 { | |
| 117 if (server_type) | |
| 118 { | |
| 119 params = g_strdup_printf("Action=open&Server=%s&IP=%s", | |
| 120 server_type, | |
| 121 servconn->http_data->gateway_ip); | |
| 122 } | |
| 123 else | |
| 124 { | |
| 125 params = g_strdup_printf("Action=open&IP=%s", | |
| 126 servconn->http_data->gateway_ip); | |
| 127 } | |
| 128 } | |
| 129 else | |
| 130 { | |
| 131 params = g_strdup_printf("SessionID=%s", | |
| 132 servconn->http_data->session_id); | |
| 133 } | |
| 134 | |
| 135 temp = g_strdup_printf( | |
| 136 "POST http://%s/gateway/gateway.dll?%s HTTP/1.1\r\n" | |
| 137 "Accept: */*\r\n" | |
| 138 "Accept-Language: en-us\r\n" | |
| 139 "User-Agent: MSMSGS\r\n" | |
| 140 "Host: %s\r\n" | |
| 141 "Proxy-Connection: Keep-Alive\r\n" | |
| 142 "Connection: Keep-Alive\r\n" | |
| 143 "Pragma: no-cache\r\n" | |
| 144 "Content-Type: application/x-msn-messenger\r\n" | |
| 145 "Content-Length: %d\r\n" | |
| 146 "\r\n" | |
| 147 "%s", | |
|
7834
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
148 ((strcmp(server_type, "SB") == 0) && first |
|
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
149 ? "gateway.messenger.hotmail.com" |
|
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
150 : servconn->http_data->gateway_ip), |
| 7288 | 151 params, |
| 152 servconn->http_data->gateway_ip, | |
| 7386 | 153 (int)size, |
| 7288 | 154 buf); |
| 155 | |
| 156 g_free(params); | |
| 157 | |
|
7834
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
158 #if 1 |
|
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
159 gaim_debug_misc("msn", "Writing HTTP to fd %d: {%s}\n", |
|
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
160 servconn->fd, temp); |
| 7288 | 161 #endif |
| 162 | |
|
7834
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
163 s = 0; |
|
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
164 needed = strlen(temp); |
|
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
165 |
|
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
166 do { |
|
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
167 res = write(servconn->fd, temp, needed); |
|
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
168 if (res >= 0) |
|
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
169 s += res; |
|
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
170 else if (errno != EAGAIN) { |
|
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
171 char *msg = g_strdup_printf("Unable to write to MSN server via HTTP (error %d)", errno); |
|
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
172 gaim_connection_error(servconn->session->account->gc, msg); |
|
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
173 g_free(msg); |
|
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
174 return -1; |
|
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
175 } |
|
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
176 } while (s < needed); |
|
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
177 |
| 7288 | 178 g_free(temp); |
| 179 | |
| 180 servconn->http_data->waiting_response = TRUE; | |
| 181 | |
| 182 servconn->http_data->virgin = FALSE; | |
| 183 | |
| 184 stop_timer(servconn); | |
| 185 | |
| 186 return s; | |
| 187 } | |
| 188 | |
| 189 void | |
| 190 msn_http_servconn_poll(MsnServConn *servconn) | |
| 191 { | |
| 192 size_t s; | |
| 193 char *temp; | |
| 194 | |
| 195 g_return_if_fail(servconn != NULL); | |
| 196 g_return_if_fail(servconn->http_data != NULL); | |
| 197 | |
| 198 if (servconn->http_data->waiting_response || | |
| 199 servconn->http_data->queue != NULL) | |
| 200 { | |
| 201 return; | |
| 202 } | |
| 203 | |
| 204 temp = g_strdup_printf( | |
| 205 "POST http://%s/gateway/gateway.dll?Action=poll&SessionID=%s HTTP/1.1\r\n" | |
| 206 "Accept: */*\r\n" | |
| 207 "Accept-Language: en-us\r\n" | |
| 208 "User-Agent: MSMSGS\r\n" | |
| 209 "Host: %s\r\n" | |
| 210 "Proxy-Connection: Keep-Alive\r\n" | |
| 211 "Connection: Keep-Alive\r\n" | |
| 212 "Pragma: no-cache\r\n" | |
| 213 "Content-Type: application/x-msn-messenger\r\n" | |
| 214 "Content-Length: 0\r\n" | |
| 215 "\r\n", | |
| 216 servconn->http_data->gateway_ip, | |
| 217 servconn->http_data->session_id, | |
| 218 servconn->http_data->gateway_ip); | |
| 219 | |
| 220 #if 0 | |
| 221 gaim_debug_misc("msn", "Writing to HTTP: {%s}\n", temp); | |
| 222 #endif | |
| 223 | |
| 224 s = write(servconn->fd, temp, strlen(temp)); | |
| 225 | |
| 226 g_free(temp); | |
| 227 | |
| 228 servconn->http_data->waiting_response = TRUE; | |
| 229 | |
| 230 stop_timer(servconn); | |
| 231 | |
| 232 if (s <= 0) | |
| 233 gaim_connection_error(servconn->session->account->gc, | |
| 234 _("Write error")); | |
| 235 } | |
| 236 | |
| 237 gboolean | |
| 238 msn_http_servconn_parse_data(MsnServConn *servconn, const char *buf, | |
| 239 size_t size, char **ret_buf, size_t *ret_size, | |
| 240 gboolean *error) | |
| 241 { | |
| 242 GaimConnection *gc; | |
| 243 const char *s, *c; | |
| 244 char *headers, *body; | |
| 245 char *tmp; | |
| 246 size_t len = 0; | |
| 247 | |
| 248 g_return_val_if_fail(servconn != NULL, FALSE); | |
| 249 g_return_val_if_fail(buf != NULL, FALSE); | |
| 250 g_return_val_if_fail(size > 0, FALSE); | |
| 251 g_return_val_if_fail(ret_buf != NULL, FALSE); | |
| 252 g_return_val_if_fail(ret_size != NULL, FALSE); | |
| 253 g_return_val_if_fail(error != NULL, FALSE); | |
| 254 | |
|
7834
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
255 #if 0 |
|
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
256 gaim_debug_info("msn", "parsing data {%s} from fd %d\n", buf, servconn->fd); |
|
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
257 #endif |
| 7288 | 258 servconn->http_data->waiting_response = FALSE; |
| 259 | |
| 260 gc = gaim_account_get_connection(servconn->session->account); | |
| 261 | |
| 262 /* Healthy defaults. */ | |
| 263 *ret_buf = NULL; | |
| 264 *ret_size = 0; | |
| 265 *error = FALSE; | |
| 266 | |
| 267 /* First, some tests to see if we have a full block of stuff. */ | |
|
7834
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
268 if (((strncmp(buf, "HTTP/1.1 200 OK\r\n", 17) != 0) && |
|
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
269 (strncmp(buf, "HTTP/1.1 100 Continue\r\n", 23) != 0)) && |
|
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
270 ((strncmp(buf, "HTTP/1.0 200 OK\r\n", 17) != 0) && |
|
99ffabc6ce73
[gaim-migrate @ 8487]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
271 (strncmp(buf, "HTTP/1.0 100 Continue\r\n", 23) != 0))) |
| 7288 | 272 { |
| 273 *error = TRUE; | |
| 274 return FALSE; | |
| 275 } | |
| 276 | |
| 277 if (strncmp(buf, "HTTP/1.1 100 Continue\r\n", 23) == 0) | |
| 278 { | |
| 279 if ((s = strstr(buf, "\r\n\r\n")) == NULL) | |
| 280 return FALSE; | |
| 281 | |
| 282 s += 4; | |
| 283 | |
| 284 if (*s == '\0') | |
| 285 { | |
| 286 *ret_buf = g_strdup(""); | |
| 287 *ret_size = 0; | |
| 288 | |
| 289 return TRUE; | |
| 290 } | |
| 291 | |
| 292 buf = s; | |
| 293 size -= (s - buf); | |
| 294 } | |
| 295 | |
| 296 if ((s = strstr(buf, "\r\n\r\n")) == NULL) | |
| 297 return FALSE; | |
| 298 | |
| 299 headers = g_strndup(buf, s - buf); | |
| 300 s += 4; /* Skip \r\n */ | |
| 301 body = g_strndup(s, size - (s - buf)); | |
| 302 | |
| 303 #if 0 | |
| 304 gaim_debug_misc("msn", "Incoming HTTP buffer: {%s\r\n%s}", headers, body); | |
| 305 #endif | |
| 306 | |
| 307 if ((s = strstr(headers, "Content-Length: ")) != NULL) | |
| 308 { | |
| 309 s += strlen("Content-Length: "); | |
| 310 | |
| 311 if ((c = strchr(s, '\r')) == NULL) | |
| 312 { | |
| 313 g_free(headers); | |
| 314 g_free(body); | |
| 315 | |
| 316 return FALSE; | |
| 317 } | |
| 318 | |
| 319 tmp = g_strndup(s, c - s); | |
| 320 len = atoi(tmp); | |
| 321 g_free(tmp); | |
| 322 | |
| 323 if (strlen(body) != len) | |
| 324 { | |
| 325 g_free(headers); | |
| 326 g_free(body); | |
| 327 | |
| 328 gaim_debug_warning("msn", | |
| 329 "body length (%d) != content length (%d)\n", | |
| 330 strlen(body), len); | |
| 331 return FALSE; | |
| 332 } | |
| 333 } | |
| 334 | |
| 335 /* Now we should be able to process the data. */ | |
| 336 if ((s = strstr(headers, "X-MSN-Messenger: ")) != NULL) | |
| 337 { | |
| 338 char *session_id, *gw_ip; | |
| 339 char *c2, *s2; | |
| 340 | |
| 341 s += strlen("X-MSN-Messenger: "); | |
| 342 | |
| 343 if ((c = strchr(s, '\r')) == NULL) | |
| 344 { | |
| 345 gaim_connection_error(gc, "Malformed X-MSN-Messenger field."); | |
| 346 return FALSE; | |
| 347 } | |
| 348 | |
| 349 tmp = g_strndup(s, c - s); | |
| 350 | |
| 351 /* Find the value for the Session ID */ | |
| 352 if ((s2 = strchr(tmp, '=')) == NULL) | |
| 353 { | |
| 354 gaim_connection_error(gc, "Malformed X-MSN-Messenger field."); | |
| 355 return FALSE; | |
| 356 } | |
| 357 | |
| 358 s2++; | |
| 359 | |
| 360 /* Terminate the ; so we can g_strdup it. */ | |
| 361 if ((c2 = strchr(s2, ';')) == NULL) | |
| 362 { | |
| 363 gaim_connection_error(gc, "Malformed X-MSN-Messenger field."); | |
| 364 return FALSE; | |
| 365 } | |
| 366 | |
| 367 *c2 = '\0'; | |
| 368 c2++; | |
| 369 | |
| 370 /* Now grab that session ID. */ | |
| 371 session_id = g_strdup(s2); | |
| 372 | |
| 373 /* Continue to the gateway IP */ | |
| 374 if ((s2 = strchr(c2, '=')) == NULL) | |
| 375 { | |
| 376 gaim_connection_error(gc, "Malformed X-MSN-Messenger field."); | |
| 377 return FALSE; | |
| 378 } | |
| 379 | |
| 380 s2++; | |
| 381 | |
| 382 /* Grab the gateway IP */ | |
| 383 gw_ip = g_strdup(s2); | |
| 384 | |
| 385 g_free(tmp); | |
| 386 | |
| 387 /* Set the new data. */ | |
| 388 if (servconn->http_data->session_id != NULL) | |
| 389 g_free(servconn->http_data->session_id); | |
| 390 | |
| 391 if (servconn->http_data->old_gateway_ip != NULL) | |
| 392 g_free(servconn->http_data->old_gateway_ip); | |
| 393 | |
| 394 servconn->http_data->old_gateway_ip = servconn->http_data->gateway_ip; | |
| 395 | |
| 396 servconn->http_data->session_id = session_id; | |
| 397 servconn->http_data->gateway_ip = gw_ip; | |
| 398 } | |
| 399 | |
| 400 g_free(headers); | |
| 401 | |
| 402 *ret_buf = body; | |
| 403 *ret_size = len; | |
| 404 | |
| 405 if (servconn->http_data->queue != NULL) | |
| 406 { | |
| 407 MsnHttpQueueData *queue_data; | |
| 408 | |
| 409 queue_data = (MsnHttpQueueData *)servconn->http_data->queue->data; | |
| 410 | |
| 411 servconn->http_data->queue = | |
| 412 g_list_remove(servconn->http_data->queue, queue_data); | |
| 413 | |
| 414 msn_http_servconn_write(queue_data->servconn, | |
| 415 queue_data->buffer, | |
| 416 queue_data->size, | |
| 417 queue_data->server_type); | |
| 418 | |
| 419 g_free(queue_data->buffer); | |
| 420 g_free(queue_data); | |
| 421 } | |
| 422 else | |
| 423 start_timer(servconn); | |
| 424 | |
| 425 return TRUE; | |
| 426 } | |
| 427 |
