int roadmap_io_read (RoadMapIO *io, void *data, int size) { switch (io->subsystem) { case ROADMAP_IO_FILE: return roadmap_file_read (io->os.file, data, size); case ROADMAP_IO_NET: return roadmap_net_receive (io->os.socket, data, size); case ROADMAP_IO_PIPE: return roadmap_spawn_read_pipe (io->os.pipe, data, size); case ROADMAP_IO_NULL: return 0; /* Cannot receive anything from there. */ } return -1; }
static int roadmap_http_decode_header (RoadMapSocket fd, char *buffer, int *sizeof_buffer, RoadMapDownloadCallbackError error) { int received_status = 0; int shift; int size; int total; int received; char *p; char *next; size = 0; total = 0; for (;;) { buffer[total] = 0; if (strchr (buffer, '\n') == NULL) { /* We do not have a full line: we need more data. */ received = roadmap_net_receive (fd, buffer + total, *sizeof_buffer - total - 1); if (received <= 0) { error ("Receive error"); return 0; } total += received; buffer[total] = 0; } shift = 2; next = strstr (buffer, "\r\n"); if (next == NULL) { shift = 1; next = strchr (buffer, '\n'); } if (next != NULL) { *next = 0; if (! received_status) { if (next != buffer) { if (strstr (buffer, " 200 ") == NULL) { error ("received bad status: %s", buffer); return 0; } received_status = 1; } } else { if (next == buffer) { /* An empty line signals the end of the header. Any * reminder data is part of the download: save it. */ next += shift; received = (buffer + total) - next; if (received) memcpy (buffer, next, received); *sizeof_buffer = received; return size; } if (strncasecmp (buffer, "Content-Length", sizeof("Content-Length")-1) == 0) { p = strchr (buffer, ':'); if (p == NULL) { error ("bad formed header: %s", buffer); return 0; } while (*(++p) == ' ') ; size = atoi(p); if (size <= 0) { error ("bad formed header: %s", buffer); return 0; } } } /* Move the remaining data to the beginning of the buffer * and wait for more. */ next += shift; received = (buffer + total) - next; if (received) memcpy (buffer, next, received); total = received; } } error ("No valid header received"); return 0; }
static int roadmap_httpcopy (RoadMapDownloadCallbacks *callbacks, const char *source, const char *destination) { RoadMapSocket fd; RoadMapFile file; int size; int loaded; int received; char buffer[ROADMAP_HTTP_MAX_CHUNK]; fd = roadmap_net_connect("http_get", source, 80, NULL); if (!ROADMAP_NET_IS_VALID(fd)) return 0; if (roadmap_net_send(fd, "\r\n", 2, 0) == -1) return 0; received = sizeof(buffer); size = roadmap_http_decode_header (fd, buffer, &received, callbacks->error); if (size <= 0) { roadmap_net_close (fd); return 0; /* We did not get the size. */ } if (! callbacks->size (size)) { roadmap_net_close (fd); return 0; } callbacks->progress (received); roadmap_file_remove (NULL, destination); file = roadmap_file_open(destination, "w"); if (!ROADMAP_FILE_IS_VALID(file)) { roadmap_net_close (fd); return 0; } if (received > 0) { if (roadmap_file_write(file, buffer, received) != received) { callbacks->error ("Error writing data"); goto cancel_download; } } loaded = received; while (loaded < size) { received = roadmap_net_receive (fd, buffer, sizeof(buffer)); if (received <= 0) { callbacks->error ("Receive error after %d data bytes", loaded); goto cancel_download; } if (roadmap_file_write(file, buffer, received) != received) { callbacks->error ("Error writing data"); goto cancel_download; } loaded += received; callbacks->progress (loaded); } if (loaded != size) { callbacks->error ("Receive error after %d data bytes", loaded); goto cancel_download; } roadmap_net_close (fd); roadmap_file_close(file); return 1; cancel_download: roadmap_file_close(file); roadmap_file_remove (NULL, destination); roadmap_net_close (fd); return 0; }