static int http_close(git_smart_subtransport *subtransport) { http_subtransport *t = (http_subtransport *) subtransport; clear_parser_state(t); if (t->socket.socket) { gitno_close(&t->socket); memset(&t->socket, 0x0, sizeof(gitno_socket)); } if (t->cred) { t->cred->free(t->cred); t->cred = NULL; } if (t->url_cred) { t->url_cred->free(t->url_cred); t->url_cred = NULL; } gitno_connection_data_free_ptrs(&t->connection_data); return 0; }
static int http_close(git_smart_subtransport *subtransport) { http_subtransport *t = (http_subtransport *) subtransport; clear_parser_state(t); if (t->socket.socket) { gitno_close(&t->socket); memset(&t->socket, 0x0, sizeof(gitno_socket)); } if (t->cred) { t->cred->free(t->cred); t->cred = NULL; } if (t->host) { git__free(t->host); t->host = NULL; } if (t->port) { git__free(t->port); t->port = NULL; } return 0; }
static int http_stream_write_single( git_smart_subtransport_stream *stream, const char *buffer, size_t len) { http_stream *s = (http_stream *)stream; http_subtransport *t = OWNING_SUBTRANSPORT(s); git_buf request = GIT_BUF_INIT; assert(t->connected); if (s->sent_request) { giterr_set(GITERR_NET, "Subtransport configured for only one write"); return -1; } clear_parser_state(t); if (gen_request(&request, s, len) < 0) { giterr_set(GITERR_NET, "Failed to generate request"); return -1; } if (gitno_send(&t->socket, request.ptr, request.size, 0) < 0) goto on_error; if (len && gitno_send(&t->socket, buffer, len, 0) < 0) goto on_error; git_buf_free(&request); s->sent_request = 1; return 0; on_error: git_buf_free(&request); return -1; }
static int http_stream_write_chunked( git_smart_subtransport_stream *stream, const char *buffer, size_t len) { http_stream *s = (http_stream *)stream; http_subtransport *t = OWNING_SUBTRANSPORT(s); assert(t->connected); /* Send the request, if necessary */ if (!s->sent_request) { git_buf request = GIT_BUF_INIT; clear_parser_state(t); if (gen_request(&request, s, 0) < 0) { giterr_set(GITERR_NET, "Failed to generate request"); return -1; } if (gitno_send(&t->socket, request.ptr, request.size, 0) < 0) { git_buf_free(&request); return -1; } git_buf_free(&request); s->sent_request = 1; } if (len > CHUNK_SIZE) { /* Flush, if necessary */ if (s->chunk_buffer_len > 0) { if (write_chunk(&t->socket, s->chunk_buffer, s->chunk_buffer_len) < 0) return -1; s->chunk_buffer_len = 0; } /* Write chunk directly */ if (write_chunk(&t->socket, buffer, len) < 0) return -1; } else { /* Append as much to the buffer as we can */ int count = min(CHUNK_SIZE - s->chunk_buffer_len, len); if (!s->chunk_buffer) s->chunk_buffer = git__malloc(CHUNK_SIZE); memcpy(s->chunk_buffer + s->chunk_buffer_len, buffer, count); s->chunk_buffer_len += count; buffer += count; len -= count; /* Is the buffer full? If so, then flush */ if (CHUNK_SIZE == s->chunk_buffer_len) { if (write_chunk(&t->socket, s->chunk_buffer, s->chunk_buffer_len) < 0) return -1; s->chunk_buffer_len = 0; if (len > 0) { memcpy(s->chunk_buffer, buffer, len); s->chunk_buffer_len = len; } } } return 0; }
static int http_stream_read( git_smart_subtransport_stream *stream, char *buffer, size_t buf_size, size_t *bytes_read) { http_stream *s = (http_stream *)stream; http_subtransport *t = OWNING_SUBTRANSPORT(s); parser_context ctx; size_t bytes_parsed; replay: *bytes_read = 0; assert(t->connected); if (!s->sent_request) { git_buf request = GIT_BUF_INIT; clear_parser_state(t); if (gen_request(&request, s, 0) < 0) { giterr_set(GITERR_NET, "Failed to generate request"); return -1; } if (gitno_send(&t->socket, request.ptr, request.size, 0) < 0) { git_buf_free(&request); return -1; } git_buf_free(&request); s->sent_request = 1; } if (!s->received_response) { if (s->chunked) { assert(s->verb == post_verb); /* Flush, if necessary */ if (s->chunk_buffer_len > 0 && write_chunk(&t->socket, s->chunk_buffer, s->chunk_buffer_len) < 0) return -1; s->chunk_buffer_len = 0; /* Write the final chunk. */ if (gitno_send(&t->socket, "0\r\n\r\n", 5, 0) < 0) return -1; } s->received_response = 1; } while (!*bytes_read && !t->parse_finished) { t->parse_buffer.offset = 0; if (gitno_recv(&t->parse_buffer) < 0) return -1; /* This call to http_parser_execute will result in invocations of the * on_* family of callbacks. The most interesting of these is * on_body_fill_buffer, which is called when data is ready to be copied * into the target buffer. We need to marshal the buffer, buf_size, and * bytes_read parameters to this callback. */ ctx.t = t; ctx.s = s; ctx.buffer = buffer; ctx.buf_size = buf_size; ctx.bytes_read = bytes_read; /* Set the context, call the parser, then unset the context. */ t->parser.data = &ctx; bytes_parsed = http_parser_execute(&t->parser, &t->settings, t->parse_buffer.data, t->parse_buffer.offset); t->parser.data = NULL; /* If there was a handled authentication failure, then parse_error * will have signaled us that we should replay the request. */ if (PARSE_ERROR_REPLAY == t->parse_error) { s->sent_request = 0; if (http_connect(t) < 0) return -1; goto replay; } if (t->parse_error < 0) return -1; if (bytes_parsed != t->parse_buffer.offset) { giterr_set(GITERR_NET, "HTTP parser error: %s", http_errno_description((enum http_errno)t->parser.http_errno)); return -1; } } return 0; }