]>
git.proxmox.com Git - libgit2.git/blob - src/netops.c
2 * Copyright (C) the libgit2 contributors. All rights reserved.
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
11 #include "git2/errors.h"
15 #include "http_parser.h"
18 int gitno_recv(gitno_buffer
*buf
)
20 return buf
->recv(buf
);
23 void gitno_buffer_setup_callback(
27 int (*recv
)(gitno_buffer
*buf
), void *cb_data
)
29 memset(data
, 0x0, len
);
34 buf
->cb_data
= cb_data
;
37 static int recv_stream(gitno_buffer
*buf
)
39 git_stream
*io
= (git_stream
*) buf
->cb_data
;
42 ret
= git_stream_read(io
, buf
->data
+ buf
->offset
, buf
->len
- buf
->offset
);
50 void gitno_buffer_setup_fromstream(git_stream
*st
, gitno_buffer
*buf
, char *data
, size_t len
)
52 memset(data
, 0x0, len
);
56 buf
->recv
= recv_stream
;
60 /* Consume up to ptr and move the rest of the buffer to the beginning */
61 void gitno_consume(gitno_buffer
*buf
, const char *ptr
)
65 assert(ptr
- buf
->data
>= 0);
66 assert(ptr
- buf
->data
<= (int) buf
->len
);
68 consumed
= ptr
- buf
->data
;
70 memmove(buf
->data
, ptr
, buf
->offset
- consumed
);
71 memset(buf
->data
+ buf
->offset
, 0x0, buf
->len
- buf
->offset
);
72 buf
->offset
-= consumed
;
75 /* Consume const bytes and move the rest of the buffer to the beginning */
76 void gitno_consume_n(gitno_buffer
*buf
, size_t cons
)
78 memmove(buf
->data
, buf
->data
+ cons
, buf
->len
- buf
->offset
);
79 memset(buf
->data
+ cons
, 0x0, buf
->len
- buf
->offset
);
83 /* Match host names according to RFC 2818 rules */
84 int gitno__match_host(const char *pattern
, const char *host
)
87 char c
= git__tolower(*pattern
++);
90 return *host
? -1 : 0;
94 /* '*' at the end matches everything left */
99 * We've found a pattern, so move towards the next matching
100 * char. The '.' is handled specially because wildcards aren't
101 * allowed to cross subdomains.
105 char h
= git__tolower(*host
);
107 return gitno__match_host(pattern
, host
++);
109 return gitno__match_host(pattern
, host
);
115 if (c
!= git__tolower(*host
++))
122 static const char *prefix_http
= "http://";
123 static const char *prefix_https
= "https://";
125 int gitno_connection_data_from_url(
126 gitno_connection_data
*data
,
128 const char *service_suffix
)
131 const char *default_port
= NULL
, *path_search_start
= NULL
;
132 char *original_host
= NULL
;
134 /* service_suffix is optional */
137 /* Save these for comparison later */
138 original_host
= data
->host
;
140 gitno_connection_data_free_ptrs(data
);
142 if (!git__prefixcmp(url
, prefix_http
)) {
143 path_search_start
= url
+ strlen(prefix_http
);
147 giterr_set(GITERR_NET
, "redirect from HTTPS to HTTP is not allowed");
150 } else if (!git__prefixcmp(url
, prefix_https
)) {
151 path_search_start
= url
+ strlen(prefix_https
);
152 default_port
= "443";
153 data
->use_ssl
= true;
154 } else if (url
[0] == '/')
155 default_port
= data
->use_ssl
? "443" : "80";
158 giterr_set(GITERR_NET
, "unrecognized URL prefix");
162 error
= gitno_extract_url_parts(
163 &data
->host
, &data
->port
, &data
->path
, &data
->user
, &data
->pass
,
167 /* Relative redirect; reuse original host name and port */
168 path_search_start
= url
;
169 git__free(data
->host
);
170 data
->host
= original_host
;
171 original_host
= NULL
;
175 const char *path
= strchr(path_search_start
, '/');
176 size_t pathlen
= strlen(path
);
177 size_t suffixlen
= service_suffix
? strlen(service_suffix
) : 0;
180 !memcmp(path
+ pathlen
- suffixlen
, service_suffix
, suffixlen
)) {
181 git__free(data
->path
);
182 data
->path
= git__strndup(path
, pathlen
- suffixlen
);
184 git__free(data
->path
);
185 data
->path
= git__strdup(path
);
188 /* Check for errors in the resulting data */
189 if (original_host
&& url
[0] != '/' && strcmp(original_host
, data
->host
)) {
190 giterr_set(GITERR_NET
, "cross host redirect not allowed");
196 if (original_host
) git__free(original_host
);
200 void gitno_connection_data_free_ptrs(gitno_connection_data
*d
)
202 git__free(d
->host
); d
->host
= NULL
;
203 git__free(d
->port
); d
->port
= NULL
;
204 git__free(d
->path
); d
->path
= NULL
;
205 git__free(d
->user
); d
->user
= NULL
;
206 git__free(d
->pass
); d
->pass
= NULL
;
209 int gitno_extract_url_parts(
216 const char *default_port
)
218 struct http_parser_url u
= {0};
219 bool has_host
, has_port
, has_path
, has_userinfo
;
220 git_buf host
= GIT_BUF_INIT
,
223 username
= GIT_BUF_INIT
,
224 password
= GIT_BUF_INIT
;
227 if (http_parser_parse_url(url
, strlen(url
), false, &u
)) {
228 giterr_set(GITERR_NET
, "malformed URL '%s'", url
);
229 error
= GIT_EINVALIDSPEC
;
233 has_host
= !!(u
.field_set
& (1 << UF_HOST
));
234 has_port
= !!(u
.field_set
& (1 << UF_PORT
));
235 has_path
= !!(u
.field_set
& (1 << UF_PATH
));
236 has_userinfo
= !!(u
.field_set
& (1 << UF_USERINFO
));
239 const char *url_host
= url
+ u
.field_data
[UF_HOST
].off
;
240 size_t url_host_len
= u
.field_data
[UF_HOST
].len
;
241 git_buf_decode_percent(&host
, url_host
, url_host_len
);
245 const char *url_port
= url
+ u
.field_data
[UF_PORT
].off
;
246 size_t url_port_len
= u
.field_data
[UF_PORT
].len
;
247 git_buf_put(&port
, url_port
, url_port_len
);
249 git_buf_puts(&port
, default_port
);
252 if (has_path
&& path_out
) {
253 const char *url_path
= url
+ u
.field_data
[UF_PATH
].off
;
254 size_t url_path_len
= u
.field_data
[UF_PATH
].len
;
255 git_buf_decode_percent(&path
, url_path
, url_path_len
);
256 } else if (path_out
) {
257 giterr_set(GITERR_NET
, "invalid url, missing path");
258 error
= GIT_EINVALIDSPEC
;
263 const char *url_userinfo
= url
+ u
.field_data
[UF_USERINFO
].off
;
264 size_t url_userinfo_len
= u
.field_data
[UF_USERINFO
].len
;
265 const char *colon
= memchr(url_userinfo
, ':', url_userinfo_len
);
268 const char *url_username
= url_userinfo
;
269 size_t url_username_len
= colon
- url_userinfo
;
270 const char *url_password
= colon
+ 1;
271 size_t url_password_len
= url_userinfo_len
- (url_username_len
+ 1);
273 git_buf_decode_percent(&username
, url_username
, url_username_len
);
274 git_buf_decode_percent(&password
, url_password
, url_password_len
);
276 git_buf_decode_percent(&username
, url_userinfo
, url_userinfo_len
);
280 if (git_buf_oom(&host
) ||
281 git_buf_oom(&port
) ||
282 git_buf_oom(&path
) ||
283 git_buf_oom(&username
) ||
284 git_buf_oom(&password
))
287 *host_out
= git_buf_detach(&host
);
288 *port_out
= git_buf_detach(&port
);
290 *path_out
= git_buf_detach(&path
);
291 *username_out
= git_buf_detach(&username
);
292 *password_out
= git_buf_detach(&password
);
298 git_buf_free(&username
);
299 git_buf_free(&password
);