/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #include "netops.h" #include #include "git2/errors.h" #include "posix.h" #include "buffer.h" #include "http_parser.h" #include "global.h" int gitno_recv(gitno_buffer *buf) { return buf->recv(buf); } void gitno_buffer_setup_callback( gitno_buffer *buf, char *data, size_t len, int (*recv)(gitno_buffer *buf), void *cb_data) { memset(data, 0x0, len); buf->data = data; buf->len = len; buf->offset = 0; buf->recv = recv; buf->cb_data = cb_data; } static int recv_stream(gitno_buffer *buf) { git_stream *io = (git_stream *) buf->cb_data; size_t readlen = buf->len - buf->offset; ssize_t ret; readlen = min(readlen, INT_MAX); ret = git_stream_read(io, buf->data + buf->offset, (int)readlen); if (ret < 0) return -1; buf->offset += ret; return (int)ret; } void gitno_buffer_setup_fromstream(git_stream *st, gitno_buffer *buf, char *data, size_t len) { memset(data, 0x0, len); buf->data = data; buf->len = len; buf->offset = 0; buf->recv = recv_stream; buf->cb_data = st; } /* Consume up to ptr and move the rest of the buffer to the beginning */ void gitno_consume(gitno_buffer *buf, const char *ptr) { size_t consumed; assert(ptr - buf->data >= 0); assert(ptr - buf->data <= (int) buf->len); consumed = ptr - buf->data; memmove(buf->data, ptr, buf->offset - consumed); memset(buf->data + buf->offset, 0x0, buf->len - buf->offset); buf->offset -= consumed; } /* Consume const bytes and move the rest of the buffer to the beginning */ void gitno_consume_n(gitno_buffer *buf, size_t cons) { memmove(buf->data, buf->data + cons, buf->len - buf->offset); memset(buf->data + cons, 0x0, buf->len - buf->offset); buf->offset -= cons; } /* Match host names according to RFC 2818 rules */ int gitno__match_host(const char *pattern, const char *host) { for (;;) { char c = git__tolower(*pattern++); if (c == '\0') return *host ? -1 : 0; if (c == '*') { c = *pattern; /* '*' at the end matches everything left */ if (c == '\0') return 0; /* * We've found a pattern, so move towards the next matching * char. The '.' is handled specially because wildcards aren't * allowed to cross subdomains. */ while(*host) { char h = git__tolower(*host); if (c == h) return gitno__match_host(pattern, host++); if (h == '.') return gitno__match_host(pattern, host); host++; } return -1; } if (c != git__tolower(*host++)) return -1; } return -1; } int gitno_connection_data_handle_redirect( git_net_url *url, const char *redirect_str, const char *service_suffix) { git_net_url tmp = GIT_NET_URL_INIT; int error = 0; assert(url && redirect_str); if (redirect_str[0] == '/') { git__free(url->path); if ((url->path = git__strdup(redirect_str)) == NULL) { error = -1; goto done; } } else { git_net_url *original = url; if ((error = git_net_url_parse(&tmp, redirect_str)) < 0) goto done; /* Validate that this is a legal redirection */ if (original->scheme && strcmp(original->scheme, tmp.scheme) != 0 && strcmp(tmp.scheme, "https") != 0) { git_error_set(GIT_ERROR_NET, "cannot redirect from '%s' to '%s'", original->scheme, tmp.scheme); error = -1; goto done; } if (original->host && git__strcasecmp(original->host, tmp.host) != 0) { git_error_set(GIT_ERROR_NET, "cannot redirect from '%s' to '%s'", original->host, tmp.host); error = -1; goto done; } git_net_url_swap(url, &tmp); } /* Remove the service suffix if it was given to us */ if (service_suffix) { const char *service_query = strchr(service_suffix, '?'); size_t suffix_len = service_query ? (size_t)(service_query - service_suffix) : strlen(service_suffix); size_t path_len = strlen(url->path); if (suffix_len && path_len >= suffix_len) { size_t suffix_offset = path_len - suffix_len; if (git__strncmp(url->path + suffix_offset, service_suffix, suffix_len) == 0 && (!service_query || git__strcmp(url->query, service_query + 1) == 0)) { /* Ensure we leave a minimum of '/' as the path */ if (suffix_offset == 0) suffix_offset++; url->path[suffix_offset] = '\0'; git__free(url->query); url->query = NULL; } } } done: git_net_url_dispose(&tmp); return error; }