16 #define NEONBLOWSCHUNKS
17 #ifndef NEONBLOWSCHUNKS
19 #include "../neon/src/ne_private.h"
23 #include "ne_request.h"
24 #include "ne_socket.h"
25 #include "ne_string.h"
28 #if !defined(HEADER_ERR_H)
34 extern void ERR_remove_state(
int foo);
35 extern void ENGINE_cleanup(
void);
36 extern void CONF_modules_unload(
int foo);
37 extern void ERR_free_strings(
void);
38 extern void EVP_cleanup(
void);
39 extern void CRYPTO_cleanup_all_ex_data(
void);
40 extern void CRYPTO_mem_leaks(
void * ptr);
51 #define WITH_NEON_MIN_VERSION 0x002700
52 #elif defined(NE_FEATURE_I18N)
53 #define WITH_NEON_MIN_VERSION 0x002600
55 #define WITH_NEON_MIN_VERSION 0x002500
59 #if WITH_NEON_MIN_VERSION >= 0x002600
60 #define ne_propfind_set_private(_pfh, _create_item, NULL) \
61 ne_propfind_set_private(_pfh, _create_item, NULL, NULL)
72 #define _RPMDIR_INTERNAL
74 #define _RPMDAV_INTERNAL
80 #define DAVDEBUG(_f, _list) \
81 if (((_f) < 0 && _dav_debug < 0) || ((_f) > 0 && _dav_debug)) \
91 #define READ_TIMEOUT_SECS 120
92 #define CONNECT_TIMEOUT_SECS 0
94 #define READ_TIMEOUT_SECS 120
95 #define CONNECT_TIMEOUT_SECS 0
108 int rpmioHttpRetries = 20;
109 int rpmioHttpRecurseMax = 5;
110 int rpmioHttpMaxRedirect = 20;
126 #if WITH_NEON_MIN_VERSION >= 0x002700
133 ne_request_destroy((ne_request *)u->
ctrl->
req);
137 ne_request_destroy(u->
data->
req);
144 ne_close_connection((ne_session *)u->
sess);
148 DAVDEBUG(-1, (stderr,
"<-- %s(%p) active %d\n", __FUNCTION__, u, rc));
157 if (u->
sess != NULL) {
158 ne_session_destroy((ne_session *)u->
sess);
169 ne_lockstore_destroy((ne_lock_store *)u->
lockstore);
176 DAVDEBUG(-1, (stderr,
"<-- %s(%p)\n", __FUNCTION__, u));
182 #if defined(NE_FEATURE_SSL)
183 if (ne_has_support(NE_FEATURE_SSL)) {
184 #if defined(WITH_OPENSSL)
187 CRYPTO_cleanup_all_ex_data();
191 CRYPTO_mem_leaks(NULL);
192 CONF_modules_unload(1);
196 DAVDEBUG(-1, (stderr,
"<-- %s()\n", __FUNCTION__));
199 static void davProgress(
void * userdata, off_t progress, off_t total)
206 sess = (ne_session *) u->
sess;
207 assert(sess != NULL);
209 assert(u == ne_get_session_private(sess,
"urlinfo"));
215 DAVDEBUG(-1, (stderr,
"<-- %s(%p,0x%x:0x%x) sess %p u %p\n", __FUNCTION__, userdata, (
unsigned int)progress, (
unsigned int)total, sess, u));
218 #if WITH_NEON_MIN_VERSION >= 0x002700
219 static void davNotify(
void * userdata,
220 ne_session_status status,
const ne_session_status_info *info)
222 static void davNotify(
void * userdata,
223 ne_conn_status status,
const char * info)
232 sess = (ne_session *) u->
sess;
233 assert(sess != NULL);
235 assert(u == ne_get_session_private(sess,
"urlinfo"));
243 #if WITH_NEON_MIN_VERSION >= 0x002700
246 ne_status_lookup = 0,
247 ne_status_connecting,
251 ne_status_disconnected
257 case ne_status_lookup:
260 case ne_status_connecting:
262 (void) ne_iaddr_print(info->ci.address, buf,
sizeof(buf));
263 buf[
sizeof(buf)-1] =
'\0';
266 case ne_status_connected:
269 case ne_status_sending:
273 case ne_status_recving:
277 case ne_status_disconnected:
283 (void) (*u->
notify) (u, status);
297 static const char * connstates[] = {
305 DAVDEBUG(-1, (stderr,
"--> %s(%p,%d,%p) sess %p u %p %s\n", __FUNCTION__, userdata, status, info, sess, u, connstates[ (status < 4 ? status : 4)]));
316 static void davCreateRequest(ne_request * req,
void * userdata,
317 const char * method,
const char * uri)
322 void * myprivate = NULL;
323 const char *
id =
"urlinfo";
326 assert(u->
sess != NULL);
328 sess = ne_get_session(req);
329 assert(sess == u->
sess);
331 assert(u == ne_get_session_private(sess,
"urlinfo"));
334 assert(sess != NULL);
335 myprivate = ne_get_session_private(sess,
id);
336 assert(u == myprivate);
338 DAVDEBUG(-1, (stderr,
"<-- %s(%p,%p,%s,%s) %s:%p\n", __FUNCTION__, req, userdata, method, uri,
id, myprivate));
341 static void davPreSend(ne_request * req,
void * userdata, ne_buffer * buf)
345 const char *
id =
"fd";
350 assert(u->
sess != NULL);
352 sess = ne_get_session(req);
353 assert(sess == u->
sess);
355 assert(u == ne_get_session_private(sess,
"urlinfo"));
358 fd = (
FD_t) ne_get_request_private(req,
id);
361 DAVDEBUG(1, (stderr,
"-> %s\n", buf->data));
362 DAVDEBUG(-1, (stderr,
"<-- %s(%p,%p,%p) sess %p %s %p\n", __FUNCTION__, req, userdata, buf, sess,
id, fd));
366 static int davPostSend(ne_request * req,
void * userdata,
const ne_status * status)
371 const char *
id =
"fd";
375 assert(u->
sess != NULL);
377 sess = ne_get_session(req);
378 assert(sess == u->
sess);
380 assert(u == ne_get_session_private(sess,
"urlinfo"));
383 fd = (
FD_t) ne_get_request_private(req,
id);
386 DAVDEBUG(-1, (stderr,
"<-- %s(%p,%p,%p) sess %p %s %p %s\n", __FUNCTION__, req, userdata, status, sess,
id, fd, ne_get_error(sess)));
391 static void davDestroyRequest(ne_request * req,
void * userdata)
396 const char *
id =
"fd";
400 assert(u->
sess != NULL);
402 sess = ne_get_session(req);
403 assert(sess == u->
sess);
405 assert(u == ne_get_session_private(sess,
"urlinfo"));
408 fd = (
FD_t) ne_get_request_private(req,
id);
410 DAVDEBUG(-1, (stderr,
"<-- %s(%p,%p) sess %p %s %p\n", __FUNCTION__, req, userdata, sess,
id, fd));
413 static void davDestroySession(
void * userdata)
418 void * myprivate = NULL;
419 const char *
id =
"urlinfo";
422 assert(u->
sess != NULL);
423 sess = (ne_session *) u->
sess;
425 assert(u == ne_get_session_private(sess,
"urlinfo"));
428 assert(sess != NULL);
429 myprivate = ne_get_session_private(sess,
id);
430 assert(u == myprivate);
432 DAVDEBUG(-1, (stderr,
"<-- %s(%p) sess %p %s %p\n", __FUNCTION__, userdata, sess,
id, myprivate));
436 davVerifyCert(
void *userdata,
int failures,
const ne_ssl_certificate *cert)
439 const char *hostname = (
const char *) userdata;
441 DAVDEBUG(-1, (stderr,
"--> %s(%p,%d,%p) %s\n", __FUNCTION__, userdata, failures, cert, hostname));
446 static int davConnect(
urlinfo u)
450 const char * path = NULL;
466 if (path == NULL || *path ==
'\0')
471 if (path != NULL && path[strlen(path)-1] ==
'/')
484 rc = ne_options((ne_session *)u->
sess, path, (ne_server_capabilities *)u->
capabilities);
488 { ne_server_capabilities *cap = (ne_server_capabilities *)u->
capabilities;
497 if (cap->dav_executable)
504 if (!strncmp(
"501 ", ne_get_error((ne_session *)u->
sess),
sizeof(
"501 ")-1)) {
510 if (!strncmp(
"301 ", ne_get_error((ne_session *)u->
sess),
sizeof(
"301 ")-1))
514 if (!strncmp(
"302 ", ne_get_error((ne_session *)u->
sess),
sizeof(
"302 ")-1)) {
516 if ((t = strchr(u->
url,
'\0')) != NULL)
530 DAVDEBUG(-1, (stderr,
"*** Connect to %s:%d failed(%d):\n\t%s\n", u->
host, u->
port, rc, ne_get_error((ne_session *)u->
sess)));
536 u->
httpVersion = (ne_version_pre_http11((ne_session *)u->
sess) ? 0 : 1);
541 static int davInit(
const char * url,
urlinfo * uret)
553 if (u->
url != NULL && u->
sess == NULL)
556 assert(u->
ut != u->
ut);
561 { ne_server_capabilities * capabilities;
566 ne_debug_init(stderr, rc);
572 u->
capabilities = capabilities = (ne_server_capabilities *)
xcalloc(1,
sizeof(*capabilities));
575 ne_lockstore_register((ne_lock_store *)u->
lockstore, (ne_session *)u->
sess);
581 {
const ne_inet_addr ** addrs;
583 ne_set_addrlist((ne_session *)u->
sess, addrs, n);
587 ne_set_progress((ne_session *)u->
sess, davProgress, u);
588 #if WITH_NEON_MIN_VERSION >= 0x002700
589 ne_set_notifier((ne_session *)u->
sess, davNotify, u);
591 ne_set_status((ne_session *)u->
sess, davNotify, u);
594 #if WITH_NEON_MIN_VERSION >= 0x002600
601 ne_set_useragent((ne_session *)u->
sess,
605 if (!strcasecmp(u->
scheme,
"https"))
606 ne_ssl_set_verify((ne_session *)u->
sess, davVerifyCert, (
char *)u->
host);
608 ne_set_session_private((ne_session *)u->
sess,
"urlinfo", u);
610 ne_hook_destroy_session((ne_session *)u->
sess, davDestroySession, u);
612 ne_hook_create_request((ne_session *)u->
sess, davCreateRequest, u);
613 ne_hook_pre_send((ne_session *)u->
sess, davPreSend, u);
614 ne_hook_post_send((ne_session *)u->
sess, davPostSend, u);
615 ne_hook_destroy_request((ne_session *)u->
sess, davDestroyRequest, u);
625 DAVDEBUG(-1, (stderr,
"<-- %s(%s) u->url %s\n", __FUNCTION__, url, u->
url));
628 u =
urlFree(u,
"urlSplit (davInit)");
641 struct fetch_resource_s {
643 struct fetch_resource_s *next;
647 enum fetch_rtype_e type;
657 GENfree(
struct fetch_resource_s *)
661 static void *fetch_destroy_item(
struct fetch_resource_s *res)
665 ne_free(res->error_reason);
672 static void *fetch_destroy_list(
struct fetch_resource_s *res)
675 struct fetch_resource_s *next;
676 for (; res != NULL; res = next) {
678 res = fetch_destroy_item(res);
684 #if WITH_NEON_MIN_VERSION >= 0x002600
685 static void *fetch_create_item(
void *userdata,
const ne_uri *uri)
687 static void *fetch_create_item(
void *userdata,
const char *uri)
691 struct fetch_resource_s * res = (
struct fetch_resource_s *) ne_calloc(
sizeof(*res));
699 static const ne_propname fetch_props[] = {
700 {
"DAV:",
"getcontentlength" },
701 {
"DAV:",
"getlastmodified" },
702 {
"http://apache.org/dav/props/",
"executable" },
703 {
"DAV:",
"resourcetype" },
704 {
"DAV:",
"checked-in" },
705 {
"DAV:",
"checked-out" },
710 #define ELM_resourcetype (NE_PROPS_STATE_TOP + 1)
711 #define ELM_collection (NE_PROPS_STATE_TOP + 2)
715 static const struct ne_xml_idmap fetch_idmap[] = {
716 {
"DAV:",
"resourcetype", ELM_resourcetype },
717 {
"DAV:",
"collection", ELM_collection }
721 static int fetch_startelm(
void *userdata,
int parent,
722 const char *nspace,
const char *
name,
726 ne_propfind_handler *pfh = (ne_propfind_handler *) userdata;
727 struct fetch_resource_s *r = (
struct fetch_resource_s *)
728 ne_propfind_current_private(pfh);
730 int state = ne_xml_mapid(fetch_idmap, NE_XML_MAPLEN(fetch_idmap),
735 !((parent == NE_207_STATE_PROP && state == ELM_resourcetype) ||
736 (parent == ELM_resourcetype && state == ELM_collection)))
737 return NE_XML_DECLINE;
739 if (state == ELM_collection) {
740 r->type = resr_collection;
746 static int fetch_compare(
const struct fetch_resource_s *r1,
747 const struct fetch_resource_s *r2)
751 if (r1->type == resr_error) {
753 }
else if (r2->type == resr_error) {
755 }
else if (r1->type == resr_collection) {
756 if (r2->type != resr_collection) {
759 return strcmp(r1->uri, r2->uri);
762 if (r2->type != resr_collection) {
763 return strcmp(r1->uri, r2->uri);
770 #if WITH_NEON_MIN_VERSION >= 0x002600
771 static void fetch_results(
void *userdata,
const ne_uri *uarg,
772 const ne_prop_result_set *
set)
774 static void fetch_results(
void *userdata,
void *uarg,
775 const ne_prop_result_set *
set)
779 rpmavx avx = (rpmavx) userdata;
780 struct fetch_resource_s *
current, *previous, *newres;
781 const char *clength, *modtime, *isexec;
782 const char *checkin, *checkout;
783 const ne_status *status = NULL;
784 const char * path = NULL;
786 #if WITH_NEON_MIN_VERSION >= 0x002600
787 const ne_uri * uri = uarg;
788 (void)
urlPath(uri->path, &path);
790 const char * uri = uarg;
796 newres = (
struct fetch_resource_s *) ne_propset_private(
set);
798 DAVDEBUG(-1, (stderr,
"==> %s in uri %s\n", path, avx->uri));
800 if (ne_path_compare(avx->uri, path) == 0) {
802 DAVDEBUG(-1, (stderr,
"==> %s skipping target resource.\n", path));
810 newres->uri = ne_strdup(path);
812 clength = ne_propset_value(
set, &fetch_props[0]);
813 modtime = ne_propset_value(
set, &fetch_props[1]);
814 isexec = ne_propset_value(
set, &fetch_props[2]);
815 checkin = ne_propset_value(
set, &fetch_props[4]);
816 checkout = ne_propset_value(
set, &fetch_props[5]);
819 status = ne_propset_status(
set, &fetch_props[0]);
821 status = ne_propset_status(
set, &fetch_props[1]);
823 if (newres->type == resr_normal && status != NULL) {
825 newres->error_status = status->code;
828 if (strcmp(status->reason_phrase,
"status text goes here") == 0) {
830 if (status->code == 401) {
831 desc =
_(
"Authorization Required");
832 }
else if (status->klass == 3) {
833 desc =
_(
"Redirect");
834 }
else if (status->klass == 5) {
835 desc =
_(
"Server Error");
837 desc =
_(
"Unknown Error");
839 newres->error_reason = ne_strdup(desc);
841 newres->error_reason = ne_strdup(status->reason_phrase);
843 newres->type = resr_error;
846 if (isexec && strcasecmp(isexec,
"T") == 0) {
847 newres->is_executable = 1;
849 newres->is_executable = 0;
853 newres->modtime = ne_httpdate_parse(modtime);
856 newres->size = atoi(clength);
861 }
else if (checkout) {
867 current = *(
struct fetch_resource_s **)avx->resrock;
868 for (current = (
struct fetch_resource_s *) *avx->resrock, previous = NULL;
870 previous =
current, current = current->next)
872 if (fetch_compare(current, newres) >= 0) {
877 previous->next = newres;
880 *(
struct fetch_resource_s **)avx->resrock = newres;
886 static int davFetch(
const urlinfo u, rpmavx avx)
890 const char * path = NULL;
892 struct fetch_resource_s * resitem = NULL;
893 ne_propfind_handler *pfh;
894 struct fetch_resource_s *
current, *next;
895 struct stat * st = avx->st;
901 pfh = ne_propfind_create((ne_session *)u->
sess, avx->uri, depth);
905 avx->resrock = (
void **) &resitem;
907 ne_xml_push_handler(ne_propfind_get_parser(pfh),
908 fetch_startelm, NULL, NULL, pfh);
910 ne_propfind_set_private(pfh, fetch_create_item, NULL);
912 rc = ne_propfind_named(pfh, fetch_props, fetch_results, avx);
914 ne_propfind_destroy(pfh);
916 for (current = resitem; current != NULL; current = next) {
920 next = current->next;
924 se = current->uri + strlen(current->uri);
926 if (strlen(current->uri) <= strlen(path)) {
927 st->st_mode = (S_IFDIR|0755);
930 st->st_size = current->size;
931 st->st_blocks = (st->st_size + 511)/512;
932 st->st_mtime = current->modtime;
933 st->st_atime = st->st_ctime = st->st_mtime;
934 current = (
struct fetch_resource_s *)
935 fetch_destroy_item(current);
941 while (s > current->uri && s[-1] !=
'/')
944 val = ne_strndup(s, (se - s));
947 val = ne_path_unescape(val);
950 switch (current->type) {
952 st_mode = S_IFREG | 0644;
954 case resr_collection:
955 st_mode = S_IFDIR | 0755;
956 if (S_ISDIR(st->st_mode))
966 xx = rpmavxAdd(avx, val, st_mode, current->size, current->modtime);
969 if (current == resitem && next == NULL) {
970 st->st_mode = st_mode;
971 st->st_nlink = S_ISDIR(st_mode) ? 2 : 1;
972 st->st_size = current->size;
973 st->st_blocks = (st->st_size + 511)/512;
974 st->st_mtime = current->modtime;
975 st->st_atime = st->st_ctime = st->st_mtime;
978 current = (
struct fetch_resource_s *)
979 fetch_destroy_item(current);
988 static int davHEAD(
urlinfo u,
struct stat *st)
992 const ne_status *status = NULL;
994 const char *value = NULL;
999 {
size_t nb = strlen(u->
url);
1000 st->st_mode = (u->
url[nb-1] ==
'/' ? S_IFDIR : S_IFREG);
1002 st->st_blksize = 4 * 1024;
1007 req = ne_request_create((ne_session *)u->
sess,
"HEAD", u->
url);
1013 rc = ne_request_dispatch(req);
1014 status = ne_get_status(req);
1017 DAVDEBUG(1, (stderr,
"HTTP request sent, awaiting response... %d %s\n", status->code, status->reason_phrase));
1024 if (status->klass != 2)
1029 #if defined(HAVE_NEON_NE_GET_RESPONSE_HEADER)
1031 value = ne_get_response_header(req, htag);
1040 value = ne_get_response_header(req, htag);
1047 htag =
"Content-Length";
1048 value = ne_get_response_header(req, htag);
1052 fprintf(stderr,
"Length: %s", value);
1055 st->st_size = strtoll(value, NULL, 10);
1057 st->st_blocks = (st->st_size + 511)/512;
1063 htag =
"Content-Type";
1064 value = ne_get_response_header(req, htag);
1067 fprintf(stderr,
" [%s]", value);
1068 if (!strcmp(value,
"text/html")
1069 || !strcmp(value,
"application/xhtml+xml"))
1070 st->st_blksize = 2 * 1024;
1073 htag =
"Last-Modified";
1074 value = ne_get_response_header(req, htag);
1077 fprintf(stderr,
" [%s]", value);
1078 st->st_mtime = ne_httpdate_parse(value);
1079 st->st_atime = st->st_ctime = st->st_mtime;
1083 fprintf(stderr,
"\n");
1087 ne_request_destroy(req);
1091 static int my_result(
const char * msg,
int ret, FILE * fp)
1100 fprintf(fp,
"*** %s: ", msg);
1104 fprintf(fp,
"%s: %s\n",
ftpStrerror(-ret), ne_get_error(sess));
1114 typedef struct rpmhtml_s * rpmhtml;
1132 const char * pattern;
1142 #if defined(__LCLINT__)
1154 rpmhtml htmlUnlink ( rpmhtml html)
1156 #define htmlUnlink(_html) \
1157 ((rpmhtml)rpmioUnlinkPoolItem((rpmioItem)(_html), __FUNCTION__, __FILE__, __LINE__))
1165 rpmhtml htmlLink ( rpmhtml html)
1167 #define htmlLink(_html) \
1168 ((rpmhtml)rpmioLinkPoolItem((rpmioItem)(_html), __FUNCTION__, __FILE__, __LINE__))
1176 rpmhtml htmlFree ( rpmhtml html)
1178 #define htmlFree(_html) \
1179 ((rpmhtml)rpmioFreePoolItem((rpmioItem)(_html), __FUNCTION__, __FILE__, __LINE__))
1183 static void htmlFini(
void * _html)
1187 rpmhtml html = (rpmhtml) _html;
1190 if (html->req != NULL) {
1191 ne_request_destroy(html->req);
1194 html->pattern = NULL;
1197 html->b = html->buf =
_free(html->buf);
1198 html->nb = html->nbuf = 0;
1207 if (_htmlPool == NULL) {
1208 _htmlPool =
rpmioNewPool(
"html",
sizeof(*html), -1, _html_debug,
1209 NULL, NULL, htmlFini);
1213 memset(((
char *)html)+
sizeof(html->_item), 0,
sizeof(*html)-
sizeof(html->_item));
1220 rpmhtml htmlNew(
urlinfo u, rpmavx avx)
1223 rpmhtml html = htmlGetPool(_htmlPool);
1225 html->req = ne_request_create((ne_session *)u->
sess,
"GET", u->
url);
1226 html->pattern = NULL;
1229 html->nbuf = BUFSIZ;
1230 html->buf = (
char *)
xmalloc(html->nbuf + 1 + 1);
1233 return htmlLink(html);
1238 static ssize_t htmlFill(rpmhtml html)
1241 char * b = html->buf;
1242 size_t nb = html->nbuf;
1245 if (html->b != NULL && html->nb > 0 && html->b > html->buf) {
1246 memmove(html->buf, html->b, html->nb);
1250 DAVDEBUG(-1, (stderr,
"--> %s(%p) %p[%u]\n", __FUNCTION__, html, b, (
unsigned)nb));
1253 rc = ne_read_response_block(html->req, b, nb) ;
1259 html->b = html->buf;
1261 DAVDEBUG(-1, (stderr,
"<-- %s(%p) %p[%u] rc %d\n", __FUNCTION__, html, b, (
unsigned)nb, (
int)rc));
1271 unsigned char nibble(
char c)
1274 if (c >=
'0' && c <=
'9')
1275 return (
unsigned char) (c -
'0');
1276 if (c >=
'A' && c <=
'F')
1277 return (
unsigned char)((int)(c -
'A') + 10);
1278 if (c >=
'a' && c <=
'f')
1279 return (
unsigned char)((int)(c -
'a') + 10);
1280 return (
unsigned char)
'\0';
1284 static const char * hrefpat =
"(?i)<a(?:\\s+[a-z][a-z0-9_]*(?:=(?:\"[^\"]*\"|\\S+))?)*?\\s+href=(?:\"([^\"]*)\"|(\\S+))";
1288 static int htmlParse(rpmhtml html)
1292 struct stat * st = html->avx->st;
1296 ssize_t nr = (html->b != NULL ? (ssize_t)html->nb : htmlFill(html));
1297 size_t contentLength = (nr >= 0 ? nr : 0);
1301 DAVDEBUG(-1, (stderr,
"--> %s(%p) %p[%u]\n", __FUNCTION__, html, html->buf, (
unsigned)html->nbuf));
1304 st->st_mode |= 0755;
1308 html->pattern = hrefpat;
1314 while (html->nb > 0) {
1316 const char * hbn, * lpath;
1324 mode_t st_mode = S_IFREG | 0644;
1327 assert(html->b != NULL);
1328 be = html->b + html->nb;
1330 offsets[0] = offsets[1] = -1;
1332 if (xx == 0 && offsets[0] != -1 && offsets[1] != -1) {
1335 f = html->b + offsets[0];
1336 fe = html->b + offsets[1];
1339 if (he[-1] ==
'"') he--;
1341 while (h > f && h[-1] !=
'"')
1345 nh = (size_t)(he - h);
1346 href = t = (
char *)
xmalloc(nh + 1 + 1);
1354 if (isxdigit((
int)h[0]) && isxdigit((
int)h[1])) {
1365 switch ((ut =
urlPath(href, &lpath))) {
1369 if (href[nh-1] ==
'/') {
1370 st_mode = S_IFDIR | 0755;
1373 st_mode = S_IFREG | 0644;
1379 st_mode = S_IFLNK | 0755;
1388 if ((hbn = strrchr(href,
'/')) != NULL)
1392 assert(hbn != NULL);
1396 while (g < be && *g && *g != '>
')
1398 if (g >= be || *g != '>
') {
1403 while (ge < be && *ge && *ge != '<
')
1405 if (ge >= be || *ge != '<
') {
1409 /* [g:ge) contains the URI basename. */
1410 ng = (size_t)(ge - g);
1411 gbn = t = (char *) xmalloc(ng + 1 + 1);
1412 while (g < ge && *g != '/
') /* XXX prohibit '/
' in gbn. */
1417 if (*hbn != '\0
' && *gbn != '\0
' && strcasecmp(hbn, gbn))
1418 fprintf(stderr, "\t[%s] != [%s]\n", hbn, gbn);
1421 * Heuristics to identify HTML sub-directories:
1422 * Avoid empty strings.
1423 * Both "." and ".." will be added by rpmavx.
1425 * Assume (case insensitive) basename(href) == basename(URI) is
1428 if (*hbn != '\0
' && *gbn != '\0
')
1429 if (strcmp(hbn, ".") && strcmp(hbn, ".."))
1430 if (!strcasecmp(hbn, gbn)) {
1431 size_t _st_size = (size_t)0; /* XXX HACK */
1432 time_t _st_mtime = (time_t)0; /* XXX HACK */
1433 xx = rpmavxAdd(html->avx, gbn, st_mode, _st_size, _st_mtime);
1434 /* count subdir links */
1435 if (st && S_ISDIR(st_mode)) st->st_nlink++;
1441 offsets[1] += (ge - fe);
1442 html->b += offsets[1];
1443 html->nb -= offsets[1];
1445 size_t nb = html->nb;
1446 if (nr > 0) nb -= 256; /* XXX overlap a bit if filling. */
1451 /* XXX Refill iff lowater reaches nbuf/4 (~2kB) */
1452 if (nr <= 0 || html->nb >= (html->nbuf/4))
1455 if ((nr = htmlFill(html)) >= 0)
1456 contentLength += nr;
1459 /* XXX Set directory length to no. of bytes of HTML parsed. */
1461 if (st->st_size == 0) {
1462 st->st_size = contentLength;
1463 st->st_blocks = (st->st_size + 511)/512;
1467 xx = mireSetEOptions(mire, NULL, 0);
1469 html->mires = (miRE) mireFreeAll(html->mires, html->nmires);
1472 DAVDEBUG(-1, (stderr, "<-- %s(%p) rc %d\n", __FUNCTION__, html, rc));
1476 /* HACK htmlNLST() should be rewritten to use davReq/davResp w callbacks. */
1478 static int htmlNLST(urlinfo u, rpmavx avx)
1479 /*@globals hrefpat, internalState @*/
1480 /*@modifies avx, internalState @*/
1482 rpmhtml html = htmlNew(u, avx);
1486 rc = ne_begin_request(html->req);
1487 rc = my_result("ne_begin_req(html->req)", rc, NULL);
1490 /*@switchbreak@*/ break;
1496 /*@notreached@*/ /*@switchbreak@*/ break;
1499 (void) htmlParse(html); /* XXX error code needs handling. */
1501 rc = ne_end_request(html->req);
1502 rc = my_result("ne_end_req(html->req)", rc, NULL);
1503 } while (rc == NE_RETRY);
1506 html = htmlFree(html);
1511 static int davNLST(rpmavx avx)
1512 /*@globals hrefpat, internalState @*/
1513 /*@modifies avx, internalState @*/
1516 const char * u_url = NULL; /* XXX FIXME: urlFind should save current URI */
1521 rc = davInit(avx->uri, &u);
1522 if (rc || u == NULL)
1525 if (u_url == NULL) { /* XXX FIXME: urlFind should save current URI */
1530 * Do PROPFIND through davFetch iff server supports.
1531 * Otherwise, do HEAD to get Content-length/ETag/Last-Modified,
1532 * followed by GET through htmlNLST() to find the contained href's.
1535 rc = davFetch(u, avx);
1538 rc = davHEAD(u, avx->st);
1541 if (rc == NE_OK && S_ISDIR(avx->st->st_mode))
1542 rc = htmlNLST(u, avx);
1554 if (!strncmp(
"301 ", ne_get_error((ne_session *)u->
sess),
sizeof(
"301 ")-1))
1558 if (!strncmp(
"302 ", ne_get_error((ne_session *)u->
sess),
sizeof(
"302 ")-1)) {
1559 const char * path = NULL;
1561 size_t nb = strlen(path);
1566 char * te = (
char *) strchr(u->
url,
'\0');
1568 if (te != NULL && te[-1] !=
'/') {
1574 if (u_url != NULL) {
1587 DAVDEBUG(1, (stderr,
"*** Fetch from %s:%d failed:\n\t%s\n",
1588 u->
host, u->
port, ne_get_error((ne_session *)u->
sess)));
1594 if (u_url != NULL) {
1606 static void davAcceptRanges(
void * userdata,
const char * value)
1611 if (!(u != NULL && value != NULL))
return;
1612 DAVDEBUG(-1, (stderr,
"*** u %p Accept-Ranges: %s\n", u, value));
1613 if (!strcmp(value,
"bytes"))
1615 if (!strcmp(value,
"none"))
1620 #if !defined(HAVE_NEON_NE_GET_RESPONSE_HEADER)
1621 static void davAllHeaders(
void * userdata,
const char * value)
1625 if (!(ctrl != NULL && value != NULL))
return;
1626 DAVDEBUG(1, (stderr,
"<- %s\n", value));
1631 static void davContentLength(
void * userdata,
const char * value)
1636 if (!(ctrl != NULL && value != NULL))
return;
1637 DAVDEBUG(-1, (stderr,
"*** fd %p Content-Length: %s\n", ctrl, value));
1645 static void davContentType(
void * userdata,
const char * value)
1650 if (!(ctrl != NULL && value != NULL))
return;
1651 DAVDEBUG(-1, (stderr,
"*** fd %p Content-Type: %s\n", ctrl, value));
1658 static void davContentDisposition(
void * userdata,
const char * value)
1663 if (!(ctrl != NULL && value != NULL))
return;
1664 DAVDEBUG(-1, (stderr,
"*** fd %p Content-Disposition: %s\n", ctrl, value));
1671 static void davLastModified(
void * userdata,
const char * value)
1676 if (!(ctrl != NULL && value != NULL))
return;
1677 DAVDEBUG(-1, (stderr,
"*** fd %p Last-Modified: %s\n", ctrl, value));
1685 static void davConnection(
void * userdata,
const char * value)
1690 if (!(ctrl != NULL && value != NULL))
return;
1691 DAVDEBUG(-1, (stderr,
"*** fd %p Connection: %s\n", ctrl, value));
1692 if (!strcasecmp(value,
"close"))
1694 else if (!strcasecmp(value,
"Keep-Alive"))
1704 DAVDEBUG(-1, (stderr,
"--> %s(%p,%p,%p) sess %p req %p\n", __FUNCTION__, u, ctrl, str, u->
sess, ctrl->
req));
1706 rc = ne_begin_request((ne_request *)ctrl->
req);
1707 rc = my_result(
"ne_begin_req(ctrl->req)", rc, NULL);
1715 DAVDEBUG(-1, (stderr,
"<-- %s(%p,%p,%p) sess %p req %p rc %d\n", __FUNCTION__, u, ctrl, str, u->
sess, ctrl->
req, rc));
1721 int davReq(
FD_t ctrl,
const char * httpCmd,
const char * httpArg)
1725 const ne_status *status;
1727 assert(ctrl != NULL);
1731 DAVDEBUG(-1, (stderr,
"--> %s(%p,%s,\"%s\") entry sess %p req %p\n", __FUNCTION__, ctrl, httpCmd, (httpArg ? httpArg :
""), u->
sess, ctrl->
req));
1734 ctrl =
fdLink(ctrl,
"open ctrl (davReq)");
1735 assert(ctrl != NULL);
1737 assert(u->
sess != NULL);
1739 if (ctrl->
req == (
void *)-1)
1742 assert(ctrl->
req == NULL);
1745 ctrl->
req = ne_request_create((ne_session *)u->
sess, httpCmd, httpArg);
1747 assert(ctrl->
req != NULL);
1749 ne_set_request_private((ne_request *)ctrl->
req,
"fd", ctrl);
1751 #if !defined(HAVE_NEON_NE_GET_RESPONSE_HEADER)
1752 ne_add_response_header_catcher((ne_request *)ctrl->
req, davAllHeaders, ctrl);
1754 ne_add_response_header_handler((ne_request *)ctrl->
req,
"Content-Length",
1755 davContentLength, ctrl);
1756 ne_add_response_header_handler((ne_request *)ctrl->
req,
"Content-Type",
1757 davContentType, ctrl);
1758 ne_add_response_header_handler((ne_request *)ctrl->
req,
"Content-Disposition",
1759 davContentDisposition, ctrl);
1760 ne_add_response_header_handler((ne_request *)ctrl->
req,
"Last-Modified",
1761 davLastModified, ctrl);
1762 ne_add_response_header_handler((ne_request *)ctrl->
req,
"Connection",
1763 davConnection, ctrl);
1766 if (!strcmp(httpCmd,
"PUT")) {
1767 #if defined(HAVE_NEON_NE_SEND_REQUEST_CHUNK)
1769 ne_add_request_header((ne_request *)ctrl->
req,
"Transfer-Encoding",
"chunked");
1770 ne_set_request_chunked((ne_request *)ctrl->
req, 1);
1778 #if !defined(HAVE_NEON_NE_GET_RESPONSE_HEADER)
1779 ne_add_response_header_handler((ne_request *)ctrl->
req,
"Accept-Ranges",
1780 davAcceptRanges, u);
1789 }
while (rc == NE_RETRY);
1793 status = ne_get_status((ne_request *)ctrl->
req);
1795 fprintf(stderr,
"HTTP request sent, awaiting response... %d %s\n", status->code, status->reason_phrase);
1797 switch (status->code) {
1810 fprintf(stderr,
"HTTP request sent, awaiting response... %d %s\n", status->code, status->reason_phrase);
1815 DAVDEBUG(-1, (stderr,
"<-- %s(%p,%s,\"%s\") exit sess %p req %p rc %d\n", __FUNCTION__, ctrl, httpCmd, (httpArg ? httpArg :
""), u->
sess, ctrl->
req, rc));
1817 #if defined(HAVE_NEON_NE_GET_RESPONSE_HEADER)
1818 davContentLength(ctrl,
1819 ne_get_response_header((ne_request *)ctrl->
req,
"Content-Length"));
1820 davContentType(ctrl,
1821 ne_get_response_header((ne_request *)ctrl->
req,
"Content-Type"));
1822 davContentDisposition(ctrl,
1823 ne_get_response_header((ne_request *)ctrl->
req,
"Content-Disposition"));
1824 davLastModified(ctrl,
1825 ne_get_response_header((ne_request *)ctrl->
req,
"Last-Modified"));
1827 ne_get_response_header((ne_request *)ctrl->
req,
"Connection"));
1828 if (strcmp(httpCmd,
"PUT"))
1830 ne_get_response_header((ne_request *)ctrl->
req,
"Accept-Ranges"));
1833 ctrl =
fdLink(ctrl,
"open data (davReq)");
1842 ctrl =
fdLink(ctrl,
"error data (davReq)");
1850 const char * path = NULL;
1857 assert(!(flags & O_RDWR));
1860 DAVDEBUG(-1, (stderr,
"--> %s(%s,0x%x,0%o,%p)\n", __FUNCTION__, url, flags, (
unsigned)mode, uret));
1861 rc = davInit(url, &u);
1862 if (rc || u == NULL || u->
sess == NULL)
1865 if (u->
ctrl == NULL)
1866 u->
ctrl =
fdNew(
"persist ctrl (davOpen)");
1870 if (yarnPeekLock(use) > 2
L && u->
data == NULL)
1871 u->
data =
fdNew(
"persist data (davOpen)");
1875 if (u->
ctrl->
u == NULL)
1876 fd = u->
ctrl =
fdLink(u->
ctrl,
"grab ctrl (davOpen persist ctrl)");
1877 else if (u->
data->
u == NULL)
1878 fd = u->
data =
fdLink(u->
data,
"grab ctrl (davOpen persist data)");
1880 fd =
fdNew(
"grab ctrl (davOpen)");
1890 fd->
u =
urlLink(u,
"url (davOpen)");
1891 fd =
fdLink(fd,
"grab data (davOpen)");
1903 ssize_t
davRead(
void * cookie,
char * buf,
size_t count)
1908 #if WITH_NEON_MIN_VERSION >= 0x002700
1910 u =
urlLink(fd->
u,
"url (davRead)");
1912 rc = ne_read_response_block((ne_request *)fd->
req, buf, count);
1915 if (u->
info.
status == ne_status_disconnected) {
1917 xx = ne_end_request((ne_request *)fd->
req);
1918 xx = my_result(
"davRead: ne_end_request(req)", xx, NULL);
1919 ne_request_destroy((ne_request *)fd->
req);
1920 fd->
req = (
void *)-1;
1925 u =
urlFree(u,
"url (davRead)");
1928 rc = ne_read_response_block((ne_request *)fd->
req, buf, count);
1931 DAVDEBUG(-1, (stderr,
"<-- %s(%p,%p,0x%x) rc 0x%x\n", __FUNCTION__, cookie, buf, (
unsigned)count, (
unsigned)rc));
1937 ssize_t
davWrite(
void * cookie,
const char * buf,
size_t count)
1939 #if !defined(NEONBLOWSCHUNKS) || defined(HAVE_NEON_NE_SEND_REQUEST_CHUNK) || defined(__LCLINT__)
1945 #if !defined(NEONBLOWSCHUNKS)
1948 assert(fd->
req != NULL);
1949 sess = ne_get_session((ne_request *)fd->
req);
1950 assert(sess != NULL);
1953 xx = ne_sock_fullwrite(sess->socket, buf, count);
1955 #if defined(HAVE_NEON_NE_SEND_REQUEST_CHUNK) || defined(__LCLINT__)
1956 assert(fd->
req != NULL);
1958 xx = ne_send_request_chunk((ne_request *)fd->
req, buf, count);
1967 rc = (xx == 0 ? (ssize_t)count : -1);
1969 DAVDEBUG(-1, (stderr,
"<-- %s(%p,%p,0x%x) rc 0x%x\n", __FUNCTION__, cookie, buf, (
unsigned)count, (
unsigned)rc));
1977 DAVDEBUG(-1, (stderr,
"<-- %s(%p,pos,%d) rc %d\n", __FUNCTION__, cookie, whence, rc));
1989 DAVDEBUG(-1, (stderr,
"--> %s(%p) rc %d clen %d req %p u %p\n", __FUNCTION__, fd, rc, (
int)fd->
bytesRemain, fd->
req, fd->
u));
1991 assert(fd->
req != NULL);
1992 if (fd->
req != (
void *)-1) {
1993 rc = ne_end_request((ne_request *)fd->
req);
1994 rc = my_result(
"ne_end_request(req)", rc, NULL);
1996 ne_request_destroy((ne_request *)fd->
req);
2000 DAVDEBUG(-1, (stderr,
"<-- %s(%p) rc %d\n", __FUNCTION__, fd, rc));
2006 int davMkdir(
const char * path, mode_t mode)
2009 const char * src = NULL;
2012 rc = davInit(path, &u);
2019 rc = ne_mkcol((ne_session *)u->
sess, path);
2026 DAVDEBUG(1, (stderr,
"<-- %s(%s,0%o) rc %d\n", __FUNCTION__, path, (
unsigned)mode, rc));
2033 const char * src = NULL;
2036 rc = davInit(path, &u);
2045 rc = ne_delete((ne_session *)u->
sess, path);
2050 DAVDEBUG(1, (stderr,
"<-- %s(%s) rc %d\n", __FUNCTION__, path, rc));
2054 int davRename(
const char * oldpath,
const char * newpath)
2057 const char * src = NULL;
2058 const char * dst = NULL;
2062 rc = davInit(oldpath, &u);
2067 (void)
urlPath(oldpath, &src);
2068 (void)
urlPath(newpath, &dst);
2072 rc = ne_move((ne_session *)u->
sess, overwrite, src, dst);
2077 DAVDEBUG(1, (stderr,
"<-- %s(%s,%s) rc %d\n", __FUNCTION__, oldpath, newpath, rc));
2084 const char * src = NULL;
2087 rc = davInit(path, &u);
2096 rc = ne_delete((ne_session *)u->
sess, src);
2101 DAVDEBUG(1, (stderr,
"<-- %s(%s) rc %d\n", __FUNCTION__, path, rc));
2106 static int davChdir(
const char * path)
2110 return davCommand(
"CWD", path, NULL);
2116 static const char *
statstr(
const struct stat * st,
2121 "dev 0x%x ino 0x%x mode 0%0o nlink %d uid %d gid %d rdev 0x%x size %u",
2122 (
unsigned)st->st_dev,
2123 (
unsigned)st->st_ino,
2124 (
unsigned)st->st_mode,
2125 (
unsigned)st->st_nlink,
2126 (
unsigned)st->st_uid,
2127 (
unsigned)st->st_gid,
2128 (
unsigned)st->st_rdev,
2129 (
unsigned)st->st_size);
2133 int davStat(
const char * path,
struct stat *st)
2141 DAVDEBUG(-1, (stderr,
"--> %s(%s)\n", __FUNCTION__, path));
2142 if (path == NULL || *path ==
'\0') {
2146 avx = (rpmavx) rpmavxNew(path, st);
2153 if (errno == 0)
errno = EAGAIN;
2163 DAVDEBUG(-1, (stderr,
"<-- %s(%s) rc %d\n\t%s\n", __FUNCTION__, path, rc,
statstr(st, buf)));
2164 avx = rpmavxFree(avx);
2168 int davLstat(
const char * path,
struct stat *st)
2176 if (path == NULL || *path ==
'\0') {
2180 avx = (rpmavx) rpmavxNew(path, st);
2187 if (errno == 0)
errno = EAGAIN;
2196 DAVDEBUG(-1, (stderr,
"<-- %s(%s) rc %d\n\t%s\n", __FUNCTION__, path, rc,
statstr(st, buf)));
2198 avx = rpmavxFree(avx);
2203 static int davReadlink(
const char * path,
char * buf,
size_t bufsiz)
2209 DAVDEBUG(-1, (stderr,
"<-- %s(%s) rc %d\n", __FUNCTION__, path, rc));
2231 assert(!(flags & O_RDWR));
2236 if (u->
ctrl == NULL)
2237 u->
ctrl =
fdNew(
"persist ctrl (httpOpen)");
2238 if (u->
ctrl != NULL) {
2241 if (yarnPeekLock(use) > 2
L && u->
data == NULL)
2242 u->
data =
fdNew(
"persist data (httpOpen)");
2246 if (u->
ctrl->
u == NULL)
2247 fd =
fdLink(u->
ctrl,
"grab ctrl (httpOpen persist ctrl)");
2248 else if (u->
data->
u == NULL)
2249 fd =
fdLink(u->
data,
"grab ctrl (httpOpen persist data)");
2251 fd =
fdNew(
"grab ctrl (httpOpen)");
2258 fd->
u =
urlLink(u,
"url (httpOpen)");
2259 fd =
fdLink(fd,
"grab data (httpOpen)");
2276 return avClosedir(dir);
2281 return avReaddir(dir);
2289 struct stat sb, *st = &sb;
2290 const char * uri = NULL;
2293 DAVDEBUG(-1, (stderr,
"--> %s(%s)\n", __FUNCTION__, path));
2295 if (path == NULL || *path ==
'\0') {
2302 if (path[strlen(path)-1] !=
'/')
2310 avx = (rpmavx) rpmavxNew(uri, st);
2318 if (errno == 0)
errno = EAGAIN;
2321 avdir = (AVDIR) avOpendir(uri, avx->av, avx->modes);
2325 avx = rpmavxFree(avx);
2327 return (DIR *) avdir;
2333 char *
davRealpath(
const char * path,
char * resolved_path)
2335 assert(resolved_path == NULL);