Mercurial > pidgin
annotate src/protocols/gg/lib/http.c @ 11851:3bfb2cffcef2
[gaim-migrate @ 14142]
inspired by Richard Stellingwerff's patch 1339606, this workaround for
annoying visible borders on tab close buttons is no longer required with
at least gtk 2.6 (if someone can confirm if it was fixed in 2.4 we could
remove it there too)
committer: Tailor Script <tailor@pidgin.im>
| author | Stu Tomlinson <stu@nosnilmot.com> |
|---|---|
| date | Thu, 27 Oct 2005 15:15:52 +0000 |
| parents | 3c536224f0d0 |
| children | 9cbc5967fbfd |
| rev | line source |
|---|---|
|
11546
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
1 /* $Id: http.c 13801 2005-09-14 19:10:39Z datallah $ */ |
| 11360 | 2 |
| 3 /* | |
| 4 * (C) Copyright 2001-2002 Wojtek Kaniewski <wojtekka@irc.pl> | |
| 5 * | |
| 6 * This program is free software; you can redistribute it and/or modify | |
| 7 * it under the terms of the GNU Lesser General Public License Version | |
| 8 * 2.1 as published by the Free Software Foundation. | |
| 9 * | |
| 10 * This program is distributed in the hope that it will be useful, | |
| 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 13 * GNU Lesser General Public License for more details. | |
| 14 * | |
| 15 * You should have received a copy of the GNU Lesser General Public | |
| 16 * License along with this program; if not, write to the Free Software | |
| 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, | |
| 18 * USA. | |
| 19 */ | |
| 20 | |
| 21 #include <sys/types.h> | |
|
11546
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
22 #ifndef _WIN32 |
| 11360 | 23 #include <sys/wait.h> |
| 24 #include <sys/socket.h> | |
| 25 #include <netinet/in.h> | |
| 26 #include <arpa/inet.h> | |
|
11546
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
27 #endif |
| 11360 | 28 |
| 29 #include "libgadu-config.h" | |
| 30 | |
| 31 #include <ctype.h> | |
| 32 #include <errno.h> | |
|
11546
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
33 #ifndef _WIN32 |
| 11360 | 34 #include <netdb.h> |
|
11546
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
35 #endif |
| 11360 | 36 #ifdef __GG_LIBGADU_HAVE_PTHREAD |
| 37 # include <pthread.h> | |
| 38 #endif | |
| 39 #include <stdarg.h> | |
| 40 #include <stdio.h> | |
| 41 #include <stdlib.h> | |
| 42 #include <string.h> | |
| 43 #include <unistd.h> | |
| 44 | |
| 45 #include "compat.h" | |
| 46 #include "libgadu.h" | |
| 47 | |
| 48 /* | |
| 49 * gg_http_connect() // funkcja pomocnicza | |
| 50 * | |
| 51 * rozpoczyna połączenie po http. | |
| 52 * | |
| 53 * - hostname - adres serwera | |
| 54 * - port - port serwera | |
| 55 * - async - asynchroniczne połączenie | |
| 56 * - method - metoda http (GET, POST, cokolwiek) | |
| 57 * - path - ścieżka do zasobu (musi być poprzedzona ,,/'') | |
| 58 * - header - nagłówek zapytania plus ewentualne dane dla POST | |
| 59 * | |
| 60 * zaalokowana struct gg_http, którą poźniej należy | |
| 61 * zwolnić funkcją gg_http_free(), albo NULL jeśli wystąpił błąd. | |
| 62 */ | |
| 63 struct gg_http *gg_http_connect(const char *hostname, int port, int async, const char *method, const char *path, const char *header) | |
| 64 { | |
| 65 struct gg_http *h; | |
| 66 | |
| 67 if (!hostname || !port || !method || !path || !header) { | |
| 68 gg_debug(GG_DEBUG_MISC, "// gg_http_connect() invalid arguments\n"); | |
| 69 errno = EFAULT; | |
| 70 return NULL; | |
| 71 } | |
| 72 | |
| 73 if (!(h = malloc(sizeof(*h)))) | |
| 74 return NULL; | |
| 75 memset(h, 0, sizeof(*h)); | |
| 76 | |
| 77 h->async = async; | |
| 78 h->port = port; | |
| 79 h->fd = -1; | |
| 80 h->type = GG_SESSION_HTTP; | |
| 81 | |
| 82 if (gg_proxy_enabled) { | |
| 83 char *auth = gg_proxy_auth(); | |
| 84 | |
| 85 h->query = gg_saprintf("%s http://%s:%d%s HTTP/1.0\r\n%s%s", | |
| 86 method, hostname, port, path, (auth) ? auth : | |
| 87 "", header); | |
| 88 hostname = gg_proxy_host; | |
| 89 h->port = port = gg_proxy_port; | |
| 90 | |
| 91 if (auth) | |
| 92 free(auth); | |
| 93 } else { | |
| 94 h->query = gg_saprintf("%s %s HTTP/1.0\r\n%s", | |
| 95 method, path, header); | |
| 96 } | |
| 97 | |
| 98 if (!h->query) { | |
| 99 gg_debug(GG_DEBUG_MISC, "// gg_http_connect() not enough memory for query\n"); | |
| 100 free(h); | |
| 101 errno = ENOMEM; | |
| 102 return NULL; | |
| 103 } | |
| 104 | |
| 105 gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-QUERY-----\n%s\n=> -----END-HTTP-QUERY-----\n", h->query); | |
| 106 | |
| 107 if (async) { | |
|
11546
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
108 #ifdef __GG_LIBGADU_HAVE_PTHREAD |
|
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
109 if (gg_resolve_pthread(&h->fd, &h->resolver, hostname)) { |
|
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
110 #elif defined _WIN32 |
|
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
111 if (gg_resolve_win32thread(&h->fd, &h->resolver, hostname)) { |
|
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
112 #else |
| 11360 | 113 if (gg_resolve(&h->fd, &h->pid, hostname)) { |
| 114 #endif | |
| 115 gg_debug(GG_DEBUG_MISC, "// gg_http_connect() resolver failed\n"); | |
| 116 gg_http_free(h); | |
| 117 errno = ENOENT; | |
| 118 return NULL; | |
| 119 } | |
| 120 | |
| 121 gg_debug(GG_DEBUG_MISC, "// gg_http_connect() resolver = %p\n", h->resolver); | |
| 122 | |
| 123 h->state = GG_STATE_RESOLVING; | |
| 124 h->check = GG_CHECK_READ; | |
| 125 h->timeout = GG_DEFAULT_TIMEOUT; | |
| 126 } else { | |
| 127 struct in_addr *hn, a; | |
| 128 | |
| 129 if (!(hn = gg_gethostbyname(hostname))) { | |
| 130 gg_debug(GG_DEBUG_MISC, "// gg_http_connect() host not found\n"); | |
| 131 gg_http_free(h); | |
| 132 errno = ENOENT; | |
| 133 return NULL; | |
| 134 } else { | |
| 135 a.s_addr = hn->s_addr; | |
| 136 free(hn); | |
| 137 } | |
| 138 | |
| 139 if (!(h->fd = gg_connect(&a, port, 0)) == -1) { | |
| 140 gg_debug(GG_DEBUG_MISC, "// gg_http_connect() connection failed (errno=%d, %s)\n", errno, strerror(errno)); | |
| 141 gg_http_free(h); | |
| 142 return NULL; | |
| 143 } | |
| 144 | |
| 145 h->state = GG_STATE_CONNECTING; | |
| 146 | |
| 147 while (h->state != GG_STATE_ERROR && h->state != GG_STATE_PARSING) { | |
| 148 if (gg_http_watch_fd(h) == -1) | |
| 149 break; | |
| 150 } | |
| 151 | |
| 152 if (h->state != GG_STATE_PARSING) { | |
| 153 gg_debug(GG_DEBUG_MISC, "// gg_http_connect() some strange error\n"); | |
| 154 gg_http_free(h); | |
| 155 return NULL; | |
| 156 } | |
| 157 } | |
| 158 | |
| 159 h->callback = gg_http_watch_fd; | |
| 160 h->destroy = gg_http_free; | |
| 161 | |
| 162 return h; | |
| 163 } | |
| 164 | |
| 165 #define gg_http_error(x) \ | |
| 166 close(h->fd); \ | |
| 167 h->fd = -1; \ | |
| 168 h->state = GG_STATE_ERROR; \ | |
| 169 h->error = x; \ | |
| 170 return 0; | |
| 171 | |
| 172 /* | |
| 173 * gg_http_watch_fd() | |
| 174 * | |
| 175 * przy asynchronicznej obsłudze HTTP funkcję tą należy wywołać, jeśli | |
| 176 * zmieniło się coś na obserwowanym deskryptorze. | |
| 177 * | |
| 178 * - h - struktura opisująca połączenie | |
| 179 * | |
| 180 * jeśli wszystko poszło dobrze to 0, inaczej -1. połączenie będzie | |
| 181 * zakończone, jeśli h->state == GG_STATE_PARSING. jeśli wystąpi jakiś | |
| 182 * błąd, to będzie tam GG_STATE_ERROR i odpowiedni kod błędu w h->error. | |
| 183 */ | |
| 184 int gg_http_watch_fd(struct gg_http *h) | |
| 185 { | |
| 186 gg_debug(GG_DEBUG_FUNCTION, "** gg_http_watch_fd(%p);\n", h); | |
| 187 | |
| 188 if (!h) { | |
| 189 gg_debug(GG_DEBUG_MISC, "// gg_http_watch_fd() invalid arguments\n"); | |
| 190 errno = EFAULT; | |
| 191 return -1; | |
| 192 } | |
| 193 | |
| 194 if (h->state == GG_STATE_RESOLVING) { | |
| 195 struct in_addr a; | |
| 196 | |
| 197 gg_debug(GG_DEBUG_MISC, "=> http, resolving done\n"); | |
| 198 | |
| 199 if (read(h->fd, &a, sizeof(a)) < (signed)sizeof(a) || a.s_addr == INADDR_NONE) { | |
| 200 gg_debug(GG_DEBUG_MISC, "=> http, resolver thread failed\n"); | |
| 201 gg_http_error(GG_ERROR_RESOLVING); | |
| 202 } | |
| 203 | |
| 204 close(h->fd); | |
| 205 h->fd = -1; | |
| 206 | |
|
11546
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
207 #ifdef __GG_LIBGADU_HAVE_PTHREAD |
| 11360 | 208 if (h->resolver) { |
| 209 pthread_cancel(*((pthread_t *) h->resolver)); | |
| 210 free(h->resolver); | |
| 211 h->resolver = NULL; | |
| 212 } | |
|
11546
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
213 #elif defined _WIN32 |
|
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
214 if (h->resolver) { |
|
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
215 HANDLE hnd = h->resolver; |
|
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
216 TerminateThread(hnd, 0); |
|
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
217 CloseHandle(hnd); |
|
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
218 h->resolver = NULL; |
|
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
219 } |
|
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
220 #else |
|
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
221 waitpid(h->pid, NULL, 0); |
| 11360 | 222 #endif |
| 223 | |
| 224 gg_debug(GG_DEBUG_MISC, "=> http, connecting to %s:%d\n", inet_ntoa(a), h->port); | |
| 225 | |
| 226 if ((h->fd = gg_connect(&a, h->port, h->async)) == -1) { | |
| 227 gg_debug(GG_DEBUG_MISC, "=> http, connection failed (errno=%d, %s)\n", errno, strerror(errno)); | |
| 228 gg_http_error(GG_ERROR_CONNECTING); | |
| 229 } | |
| 230 | |
| 231 h->state = GG_STATE_CONNECTING; | |
| 232 h->check = GG_CHECK_WRITE; | |
| 233 h->timeout = GG_DEFAULT_TIMEOUT; | |
| 234 | |
| 235 return 0; | |
| 236 } | |
| 237 | |
| 238 if (h->state == GG_STATE_CONNECTING) { | |
| 239 int res = 0; | |
| 240 unsigned int res_size = sizeof(res); | |
| 241 | |
| 242 if (h->async && (getsockopt(h->fd, SOL_SOCKET, SO_ERROR, &res, &res_size) || res)) { | |
| 243 gg_debug(GG_DEBUG_MISC, "=> http, async connection failed (errno=%d, %s)\n", (res) ? res : errno , strerror((res) ? res : errno)); | |
| 244 close(h->fd); | |
| 245 h->fd = -1; | |
| 246 h->state = GG_STATE_ERROR; | |
| 247 h->error = GG_ERROR_CONNECTING; | |
| 248 if (res) | |
| 249 errno = res; | |
| 250 return 0; | |
| 251 } | |
| 252 | |
| 253 gg_debug(GG_DEBUG_MISC, "=> http, connected, sending request\n"); | |
| 254 | |
| 255 h->state = GG_STATE_SENDING_QUERY; | |
| 256 } | |
| 257 | |
| 258 if (h->state == GG_STATE_SENDING_QUERY) { | |
| 259 int res; | |
| 260 | |
| 261 if ((res = write(h->fd, h->query, strlen(h->query))) < 1) { | |
| 262 gg_debug(GG_DEBUG_MISC, "=> http, write() failed (len=%d, res=%d, errno=%d)\n", strlen(h->query), res, errno); | |
| 263 gg_http_error(GG_ERROR_WRITING); | |
| 264 } | |
| 265 | |
| 266 if (res < strlen(h->query)) { | |
| 267 gg_debug(GG_DEBUG_MISC, "=> http, partial header sent (led=%d, sent=%d)\n", strlen(h->query), res); | |
| 268 | |
| 269 memmove(h->query, h->query + res, strlen(h->query) - res + 1); | |
| 270 h->state = GG_STATE_SENDING_QUERY; | |
| 271 h->check = GG_CHECK_WRITE; | |
| 272 h->timeout = GG_DEFAULT_TIMEOUT; | |
| 273 } else { | |
| 274 gg_debug(GG_DEBUG_MISC, "=> http, request sent (len=%d)\n", strlen(h->query)); | |
| 275 free(h->query); | |
| 276 h->query = NULL; | |
| 277 | |
| 278 h->state = GG_STATE_READING_HEADER; | |
| 279 h->check = GG_CHECK_READ; | |
| 280 h->timeout = GG_DEFAULT_TIMEOUT; | |
| 281 } | |
| 282 | |
| 283 return 0; | |
| 284 } | |
| 285 | |
| 286 if (h->state == GG_STATE_READING_HEADER) { | |
| 287 char buf[1024], *tmp; | |
| 288 int res; | |
| 289 | |
| 290 if ((res = read(h->fd, buf, sizeof(buf))) == -1) { | |
| 291 gg_debug(GG_DEBUG_MISC, "=> http, reading header failed (errno=%d)\n", errno); | |
| 292 if (h->header) { | |
| 293 free(h->header); | |
| 294 h->header = NULL; | |
| 295 } | |
| 296 gg_http_error(GG_ERROR_READING); | |
| 297 } | |
| 298 | |
| 299 if (!res) { | |
| 300 gg_debug(GG_DEBUG_MISC, "=> http, connection reset by peer\n"); | |
| 301 if (h->header) { | |
| 302 free(h->header); | |
| 303 h->header = NULL; | |
| 304 } | |
| 305 gg_http_error(GG_ERROR_READING); | |
| 306 } | |
| 307 | |
| 308 gg_debug(GG_DEBUG_MISC, "=> http, read %d bytes of header\n", res); | |
| 309 | |
| 310 if (!(tmp = realloc(h->header, h->header_size + res + 1))) { | |
| 311 gg_debug(GG_DEBUG_MISC, "=> http, not enough memory for header\n"); | |
| 312 free(h->header); | |
| 313 h->header = NULL; | |
| 314 gg_http_error(GG_ERROR_READING); | |
| 315 } | |
| 316 | |
| 317 h->header = tmp; | |
| 318 | |
| 319 memcpy(h->header + h->header_size, buf, res); | |
| 320 h->header_size += res; | |
| 321 | |
| 322 gg_debug(GG_DEBUG_MISC, "=> http, header_buf=%p, header_size=%d\n", h->header, h->header_size); | |
| 323 | |
| 324 h->header[h->header_size] = 0; | |
| 325 | |
| 326 if ((tmp = strstr(h->header, "\r\n\r\n")) || (tmp = strstr(h->header, "\n\n"))) { | |
| 327 int sep_len = (*tmp == '\r') ? 4 : 2; | |
| 328 unsigned int left; | |
| 329 char *line; | |
| 330 | |
| 331 left = h->header_size - ((long)(tmp) - (long)(h->header) + sep_len); | |
| 332 | |
| 333 gg_debug(GG_DEBUG_MISC, "=> http, got all header (%d bytes, %d left)\n", h->header_size - left, left); | |
| 334 | |
| 335 /* HTTP/1.1 200 OK */ | |
| 336 if (strlen(h->header) < 16 || strncmp(h->header + 9, "200", 3)) { | |
| 337 gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-HEADER-----\n%s\n=> -----END-HTTP-HEADER-----\n", h->header); | |
| 338 | |
| 339 gg_debug(GG_DEBUG_MISC, "=> http, didn't get 200 OK -- no results\n"); | |
| 340 free(h->header); | |
| 341 h->header = NULL; | |
| 342 gg_http_error(GG_ERROR_CONNECTING); | |
| 343 } | |
| 344 | |
| 345 h->body_size = 0; | |
| 346 line = h->header; | |
| 347 *tmp = 0; | |
| 348 | |
| 349 gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-HEADER-----\n%s\n=> -----END-HTTP-HEADER-----\n", h->header); | |
| 350 | |
| 351 while (line) { | |
| 352 if (!strncasecmp(line, "Content-length: ", 16)) { | |
| 353 h->body_size = atoi(line + 16); | |
| 354 } | |
| 355 line = strchr(line, '\n'); | |
| 356 if (line) | |
| 357 line++; | |
| 358 } | |
| 359 | |
| 360 if (h->body_size <= 0) { | |
| 361 gg_debug(GG_DEBUG_MISC, "=> http, content-length not found\n"); | |
| 362 h->body_size = left; | |
| 363 } | |
| 364 | |
| 365 if (left > h->body_size) { | |
| 366 gg_debug(GG_DEBUG_MISC, "=> http, oversized reply (%d bytes needed, %d bytes left)\n", h->body_size, left); | |
| 367 h->body_size = left; | |
| 368 } | |
| 369 | |
| 370 gg_debug(GG_DEBUG_MISC, "=> http, body_size=%d\n", h->body_size); | |
| 371 | |
| 372 if (!(h->body = malloc(h->body_size + 1))) { | |
| 373 gg_debug(GG_DEBUG_MISC, "=> http, not enough memory (%d bytes for body_buf)\n", h->body_size + 1); | |
| 374 free(h->header); | |
| 375 h->header = NULL; | |
| 376 gg_http_error(GG_ERROR_READING); | |
| 377 } | |
| 378 | |
| 379 if (left) { | |
| 380 memcpy(h->body, tmp + sep_len, left); | |
| 381 h->body_done = left; | |
| 382 } | |
| 383 | |
| 384 h->body[left] = 0; | |
| 385 | |
| 386 h->state = GG_STATE_READING_DATA; | |
| 387 h->check = GG_CHECK_READ; | |
| 388 h->timeout = GG_DEFAULT_TIMEOUT; | |
| 389 } | |
| 390 | |
| 391 return 0; | |
| 392 } | |
| 393 | |
| 394 if (h->state == GG_STATE_READING_DATA) { | |
| 395 char buf[1024]; | |
| 396 int res; | |
| 397 | |
| 398 if ((res = read(h->fd, buf, sizeof(buf))) == -1) { | |
| 399 gg_debug(GG_DEBUG_MISC, "=> http, reading body failed (errno=%d)\n", errno); | |
| 400 if (h->body) { | |
| 401 free(h->body); | |
| 402 h->body = NULL; | |
| 403 } | |
| 404 gg_http_error(GG_ERROR_READING); | |
| 405 } | |
| 406 | |
| 407 if (!res) { | |
| 408 if (h->body_done >= h->body_size) { | |
| 409 gg_debug(GG_DEBUG_MISC, "=> http, we're done, closing socket\n"); | |
| 410 h->state = GG_STATE_PARSING; | |
| 411 close(h->fd); | |
| 412 h->fd = -1; | |
| 413 } else { | |
| 414 gg_debug(GG_DEBUG_MISC, "=> http, connection closed while reading (have %d, need %d)\n", h->body_done, h->body_size); | |
| 415 if (h->body) { | |
| 416 free(h->body); | |
| 417 h->body = NULL; | |
| 418 } | |
| 419 gg_http_error(GG_ERROR_READING); | |
| 420 } | |
| 421 | |
| 422 return 0; | |
| 423 } | |
| 424 | |
| 425 gg_debug(GG_DEBUG_MISC, "=> http, read %d bytes of body\n", res); | |
| 426 | |
| 427 if (h->body_done + res > h->body_size) { | |
| 428 char *tmp; | |
| 429 | |
| 430 gg_debug(GG_DEBUG_MISC, "=> http, too much data (%d bytes, %d needed), enlarging buffer\n", h->body_done + res, h->body_size); | |
| 431 | |
| 432 if (!(tmp = realloc(h->body, h->body_done + res + 1))) { | |
| 433 gg_debug(GG_DEBUG_MISC, "=> http, not enough memory for data (%d needed)\n", h->body_done + res + 1); | |
| 434 free(h->body); | |
| 435 h->body = NULL; | |
| 436 gg_http_error(GG_ERROR_READING); | |
| 437 } | |
| 438 | |
| 439 h->body = tmp; | |
| 440 h->body_size = h->body_done + res; | |
| 441 } | |
| 442 | |
| 443 h->body[h->body_done + res] = 0; | |
| 444 memcpy(h->body + h->body_done, buf, res); | |
| 445 h->body_done += res; | |
| 446 | |
| 447 gg_debug(GG_DEBUG_MISC, "=> body_done=%d, body_size=%d\n", h->body_done, h->body_size); | |
| 448 | |
| 449 return 0; | |
| 450 } | |
| 451 | |
| 452 if (h->fd != -1) | |
| 453 close(h->fd); | |
| 454 | |
| 455 h->fd = -1; | |
| 456 h->state = GG_STATE_ERROR; | |
| 457 h->error = 0; | |
| 458 | |
| 459 return -1; | |
| 460 } | |
| 461 | |
| 462 #undef gg_http_error | |
| 463 | |
| 464 /* | |
| 465 * gg_http_stop() | |
| 466 * | |
| 467 * jeśli połączenie jest w trakcie, przerywa je. nie zwalnia h->data. | |
| 468 * | |
| 469 * - h - struktura opisująca połączenie | |
| 470 */ | |
| 471 void gg_http_stop(struct gg_http *h) | |
| 472 { | |
| 473 if (!h) | |
| 474 return; | |
| 475 | |
| 476 if (h->state == GG_STATE_ERROR || h->state == GG_STATE_DONE) | |
| 477 return; | |
| 478 | |
| 479 if (h->fd != -1) | |
| 480 close(h->fd); | |
| 481 h->fd = -1; | |
| 482 } | |
| 483 | |
| 484 /* | |
| 485 * gg_http_free_fields() // funkcja wewnętrzna | |
| 486 * | |
| 487 * zwalnia pola struct gg_http, ale nie zwalnia samej struktury. | |
| 488 */ | |
| 489 void gg_http_free_fields(struct gg_http *h) | |
| 490 { | |
| 491 if (!h) | |
| 492 return; | |
| 493 | |
| 494 if (h->body) { | |
| 495 free(h->body); | |
| 496 h->body = NULL; | |
| 497 } | |
| 498 | |
| 499 if (h->query) { | |
| 500 free(h->query); | |
| 501 h->query = NULL; | |
| 502 } | |
| 503 | |
| 504 if (h->header) { | |
| 505 free(h->header); | |
| 506 h->header = NULL; | |
| 507 } | |
| 508 } | |
| 509 | |
| 510 /* | |
| 511 * gg_http_free() | |
| 512 * | |
| 513 * próbuje zamknąć połączenie i zwalnia pamięć po nim. | |
| 514 * | |
| 515 * - h - struktura, którą należy zlikwidować | |
| 516 */ | |
| 517 void gg_http_free(struct gg_http *h) | |
| 518 { | |
| 519 if (!h) | |
| 520 return; | |
| 521 | |
| 522 gg_http_stop(h); | |
| 523 gg_http_free_fields(h); | |
| 524 free(h); | |
| 525 } | |
| 526 | |
| 527 /* | |
| 528 * Local variables: | |
| 529 * c-indentation-style: k&r | |
| 530 * c-basic-offset: 8 | |
| 531 * indent-tabs-mode: notnil | |
| 532 * End: | |
| 533 * | |
| 534 * vim: shiftwidth=8: | |
| 535 */ |
