lock.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  1. /*
  2. lock tests
  3. Copyright (C) 2002-2010, Joe Orton <[email protected]>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. */
  16. #include "config.h"
  17. #include <sys/types.h>
  18. #ifdef HAVE_STDLIB_H
  19. #include <stdlib.h>
  20. #endif
  21. #ifdef HAVE_UNISTD_H
  22. #include <unistd.h>
  23. #endif
  24. #include "ne_request.h"
  25. #include "ne_locks.h"
  26. #include "ne_socket.h"
  27. #include "ne_basic.h"
  28. #include "ne_auth.h"
  29. #include "tests.h"
  30. #include "child.h"
  31. #include "utils.h"
  32. #define EOL "\r\n"
  33. #define FOO_LOCKROOT "http://localhost/foo"
  34. /* returns an activelock XML element. */
  35. static char *activelock(enum ne_lock_scope scope,
  36. int depth,
  37. const char *owner,
  38. const char *uri,
  39. unsigned long timeout,
  40. const char *token_href)
  41. {
  42. static char buf[BUFSIZ];
  43. const char *lr_start = uri != NULL ? "<D:lockroot><D:href>" : "";
  44. const char *lr_end = uri != NULL ? "</D:href></D:lockroot>\n" : "";
  45. ne_snprintf(buf, BUFSIZ, \
  46. "<D:activelock>\n" \
  47. "<D:locktype><D:write/></D:locktype>\n" \
  48. "<D:lockscope><D:%s/></D:lockscope>\n" \
  49. "<D:depth>%d</D:depth>\n" \
  50. "<D:owner>%s</D:owner>\n" \
  51. "<D:timeout>Second-%lu</D:timeout>\n" \
  52. "<D:locktoken><D:href>%s</D:href></D:locktoken>\n" \
  53. "%s%s%s" \
  54. "</D:activelock>", \
  55. scope==ne_lockscope_exclusive?"exclusive":"shared", \
  56. depth, owner, timeout, token_href, \
  57. lr_start, uri ? uri : "", lr_end);
  58. return buf;
  59. }
  60. /* return body of LOCK response for given lock. */
  61. static char *lock_response(enum ne_lock_scope scope,
  62. int depth,
  63. const char *owner,
  64. const char *uri,
  65. unsigned long timeout,
  66. const char *token_href)
  67. {
  68. static char buf[BUFSIZ];
  69. ne_snprintf(buf, sizeof buf,
  70. "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
  71. "<D:prop xmlns:D=\"DAV:\">"
  72. "<D:lockdiscovery>%s</D:lockdiscovery></D:prop>\n",
  73. activelock(scope, depth, owner, uri, timeout, token_href));
  74. return buf;
  75. }
  76. /* return body of LOCK response where response gives multiple
  77. * activelocks (i.e. shared locks). */
  78. static char *multi_lock_response(struct ne_lock **locks)
  79. {
  80. ne_buffer *buf = ne_buffer_create();
  81. int n;
  82. ne_buffer_zappend(buf,
  83. "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
  84. "<D:prop xmlns:D=\"DAV:\">"
  85. "<D:lockdiscovery>");
  86. for (n = 0; locks[n] != NULL; n++) {
  87. char *lk = activelock(locks[n]->scope, locks[n]->depth,
  88. locks[n]->owner, NULL,
  89. locks[n]->timeout, locks[n]->token);
  90. ne_buffer_zappend(buf, lk);
  91. }
  92. ne_buffer_zappend(buf, "</D:lockdiscovery></D:prop>");
  93. return ne_buffer_finish(buf);
  94. }
  95. static char *discover_response(const char *href, const struct ne_lock *lk)
  96. {
  97. char buf[BUFSIZ];
  98. char *uri = ne_uri_unparse(&lk->uri);
  99. ne_snprintf(buf, BUFSIZ,
  100. "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
  101. "<D:multistatus xmlns:D='DAV:'>\n"
  102. "<D:response><D:href>%s</D:href><D:propstat>\n"
  103. "<D:prop><D:lockdiscovery>%s</D:lockdiscovery></D:prop>\n"
  104. "<D:status>HTTP/1.1 200 OK</D:status></D:propstat>\n"
  105. "</D:response></D:multistatus>\n",
  106. href, activelock(lk->scope, lk->depth, lk->owner, uri,
  107. 7200, lk->token));
  108. ne_free(uri);
  109. return ne_strdup(buf);
  110. }
  111. static struct ne_lock *make_lock(const char *path, const char *token,
  112. enum ne_lock_scope scope, int depth)
  113. {
  114. struct ne_lock *lock = ne_calloc(sizeof *lock);
  115. if (lock->token) lock->token = ne_strdup(token);
  116. lock->scope = scope;
  117. lock->depth = depth;
  118. lock->uri.host = ne_strdup("localhost");
  119. lock->uri.scheme = ne_strdup("http");
  120. lock->uri.path = ne_strdup(path);
  121. lock->uri.port = 7777;
  122. return lock;
  123. }
  124. /* Tests for lock store handling. */
  125. static int store_single(void)
  126. {
  127. ne_lock_store *store = ne_lockstore_create();
  128. struct ne_lock *lk = make_lock("/foo", "blah", ne_lockscope_exclusive, 0);
  129. struct ne_lock *lk2;
  130. ONN("create failed", store == NULL);
  131. ONN("new lock store not empty", ne_lockstore_first(store) != NULL);
  132. ne_lockstore_add(store, lk);
  133. ONN("lock not found in store", ne_lockstore_first(store) != lk);
  134. ONN(">1 locks in store?", ne_lockstore_next(store) != NULL);
  135. lk2 = ne_lockstore_findbyuri(store, &lk->uri);
  136. ONN("lock not found by URI", lk2 == NULL);
  137. ONN("other lock found by URI", lk2 != lk);
  138. ne_lockstore_remove(store, lk);
  139. ONN("store not empty after removing lock",
  140. ne_lockstore_first(store) != NULL);
  141. ONN("lock still found after removing lock",
  142. ne_lockstore_findbyuri(store, &lk->uri) != NULL);
  143. ne_lockstore_destroy(store);
  144. ne_lock_destroy(lk);
  145. return OK;
  146. }
  147. static int store_several(void)
  148. {
  149. ne_lock_store *store = ne_lockstore_create();
  150. struct ne_lock *lk = make_lock("/foo", "blah", ne_lockscope_exclusive, 0);
  151. struct ne_lock *lk2 = make_lock("/bar", "blee", ne_lockscope_exclusive, 0);
  152. struct ne_lock *lf, *lf2;
  153. ONN("create failed", store == NULL);
  154. ne_lockstore_add(store, lk);
  155. ne_lockstore_add(store, lk2);
  156. lf = ne_lockstore_first(store);
  157. ONN("lock store empty", lf == NULL);
  158. lf2 = ne_lockstore_next(store);
  159. ONN("lock store >2 locks", ne_lockstore_next(store) != NULL);
  160. /* guarantee that _first, _next returned either of the
  161. * combinations: (lf, lf2) or (lf2, lf) */
  162. ONN("found wrong locks", ((lf != lk && lf != lk2) ||
  163. (lf2 != lk && lf2 != lk2) ||
  164. (lf == lf2)));
  165. ONN("first find failed",
  166. ne_lockstore_findbyuri(store, &lk->uri) != lk);
  167. ONN("second find failed",
  168. ne_lockstore_findbyuri(store, &lk2->uri) != lk2);
  169. ne_lockstore_remove(store, lk);
  170. ne_lock_destroy(lk);
  171. ONN("remove left stray lock?", ne_lockstore_first(store) != lk2);
  172. ONN("remove left >1 lock?", ne_lockstore_next(store) != NULL);
  173. ne_lockstore_remove(store, lk2);
  174. ne_lock_destroy(lk2);
  175. ONN("store not empty after removing all locks",
  176. ne_lockstore_first(store) != NULL);
  177. ne_lockstore_destroy(store);
  178. return OK;
  179. }
  180. /* Use a fake session forced to use port 7777 to the origin, to
  181. * simplify the tests. */
  182. static int fake_session(ne_session **sess, server_fn fn, void *userdata)
  183. {
  184. return proxied_session_server(sess, "http", "localhost", 7777,
  185. fn, userdata);
  186. }
  187. /* regression test for <= 0.18.2, where timeout field was not parsed correctly. */
  188. static int lock_timeout(void)
  189. {
  190. ne_session *sess;
  191. char *resp, *rbody = lock_response(ne_lockscope_exclusive, 0, "me",
  192. NULL, 6500, "opaquelocktoken:foo");
  193. struct ne_lock *lock = ne_lock_create();
  194. resp = ne_concat("HTTP/1.1 200 OK\r\n" "Server: neon-test-server\r\n"
  195. "Content-type: application/xml" EOL
  196. "Lock-Token: <opaquelocktoken:foo>" EOL
  197. "Connection: close\r\n\r\n", rbody, NULL);
  198. CALL(fake_session(&sess, single_serve_string, resp));
  199. ne_free(resp);
  200. ne_fill_server_uri(sess, &lock->uri);
  201. lock->uri.path = ne_strdup("/foo");
  202. lock->timeout = 5;
  203. ONREQ(ne_lock(sess, lock));
  204. ONN("lock timeout ignored in response",
  205. lock->timeout != 6500);
  206. ne_session_destroy(sess);
  207. ne_lock_destroy(lock);
  208. CALL(await_server());
  209. return OK;
  210. }
  211. #define LONG_TIMEOUT (4294967295UL)
  212. /* Lock timeouts should be allowed up to 2^32-1, but ne_lock uses a
  213. * signed long to store timeouts, so this would fail with 32-bit long. */
  214. static int lock_long_timeout(void)
  215. {
  216. ne_session *sess;
  217. char *resp, *rbody = lock_response(ne_lockscope_exclusive, 0, "me", FOO_LOCKROOT,
  218. LONG_TIMEOUT, "opaquelocktoken:foo");
  219. struct ne_lock *lock = ne_lock_create();
  220. resp = ne_concat("HTTP/1.1 200 OK\r\n" "Server: neon-test-server\r\n"
  221. "Content-type: application/xml" EOL
  222. "Lock-Token: <opaquelocktoken:foo>" EOL
  223. "Connection: close\r\n\r\n", rbody, NULL);
  224. CALL(fake_session(&sess, single_serve_string, resp));
  225. ne_free(resp);
  226. ne_fill_server_uri(sess, &lock->uri);
  227. lock->uri.path = ne_strdup("/foo");
  228. lock->timeout = 5;
  229. ONREQ(ne_lock(sess, lock));
  230. ne_session_destroy(sess);
  231. ne_lock_destroy(lock);
  232. CALL(await_server());
  233. return OK;
  234. }
  235. static int verify_if;
  236. static const char *verify_if_expect;
  237. static void got_if_header(char *value)
  238. {
  239. verify_if = !strcmp(verify_if_expect, value);
  240. NE_DEBUG(NE_DBG_HTTP, "Verified If header, %d: got [%s] expected [%s]\n",
  241. verify_if, value, verify_if_expect);
  242. }
  243. /* Server callback which checks that an If: header is received. */
  244. static int serve_verify_if(ne_socket *sock, void *userdata)
  245. {
  246. /* tell us about If headers in the request. */
  247. want_header = "If";
  248. got_header = got_if_header;
  249. verify_if_expect = userdata;
  250. verify_if = 0;
  251. CALL(discard_request(sock));
  252. if (verify_if) {
  253. ON(SEND_STRING(sock, "HTTP/1.1 200 OK" EOL));
  254. } else {
  255. ON(SEND_STRING(sock, "HTTP/1.1 403 Wrong If Header" EOL));
  256. }
  257. ON(SEND_STRING(sock, "Connection: close" EOL EOL));
  258. return OK;
  259. }
  260. /* Make a request which will require a lock. */
  261. static int do_request(ne_session *sess, const char *path, int depth,
  262. int modparent)
  263. {
  264. ne_request *req = ne_request_create(sess, "RANDOM", path);
  265. if (depth > 0) {
  266. ne_add_depth_header(req, depth);
  267. }
  268. if (depth != -1)
  269. ne_lock_using_resource(req, path, depth);
  270. if (modparent)
  271. ne_lock_using_parent(req, path);
  272. ONREQ(ne_request_dispatch(req));
  273. ONV(ne_get_status(req)->code != 200,
  274. ("request failed: %s", ne_get_error(sess)));
  275. ne_request_destroy(req);
  276. return OK;
  277. }
  278. /* If modparent is non-zero; the request is flagged to
  279. * modify the parent resource too. */
  280. #define LOCK_MODPARENT (0x01)
  281. /* Enable SharePoint hacks. */
  282. #define LOCK_SHAREPOINT (0x02)
  283. /* Use a MOVE request. */
  284. #define LOCK_MOVE (0x04)
  285. /* Tests If: header submission, for a lock of depth 'lockdepth' at
  286. * 'lockpath', with a request to 'reqpath' which Depth header of
  287. * 'reqdepth'. 'flags' is bitwise-or of LOCK_* flags above. */
  288. static int submit_test2(const char *lockpath, int lockdepth,
  289. const char *path1, const char *path2,
  290. int reqdepth, unsigned int flags)
  291. {
  292. ne_lock_store *store = ne_lockstore_create();
  293. ne_session *sess;
  294. struct ne_lock *lk = ne_lock_create();
  295. char *expect_if;
  296. int ret;
  297. if (flags & LOCK_SHAREPOINT)
  298. expect_if = ne_strdup("(<somelocktoken>)");
  299. else
  300. expect_if = ne_concat("<http://localhost:7777", lockpath,
  301. "> (<somelocktoken>)", NULL);
  302. CALL(fake_session(&sess, serve_verify_if, expect_if));
  303. ne_free(expect_if);
  304. if (flags & LOCK_SHAREPOINT)
  305. ne_set_session_flag(sess, NE_SESSFLAG_SHAREPOINT, 1);
  306. ne_fill_server_uri(sess, &lk->uri);
  307. lk->uri.path = ne_strdup(lockpath);
  308. lk->token = ne_strdup("somelocktoken");
  309. lk->depth = lockdepth;
  310. /* register the lock store, and add our lock for "/foo" to it. */
  311. ne_lockstore_register(store, sess);
  312. ne_lockstore_add(store, lk);
  313. if (flags & LOCK_MOVE) {
  314. ret = ne_move(sess, 0, path1, path2);
  315. if (ret)
  316. t_context("MOVE failed: %s", ne_get_error(sess));
  317. }
  318. else
  319. ret = do_request(sess, path1, reqdepth, flags & LOCK_MODPARENT);
  320. CALL(await_server());
  321. ne_lockstore_destroy(store);
  322. ne_session_destroy(sess);
  323. return ret;
  324. }
  325. /* Tests If: header submission, for a lock of depth 'lockdepth' at
  326. * 'lockpath', with a request to 'reqpath' which Depth header of
  327. * 'reqdepth'. 'flags' is bitwise-or of LOCK_* flags above. */
  328. static int submit_test(const char *lockpath, int lockdepth,
  329. const char *reqpath, int reqdepth,
  330. unsigned int flags)
  331. {
  332. return submit_test2(lockpath, lockdepth,
  333. reqpath, NULL, reqdepth,
  334. flags);
  335. }
  336. static int if_simple(void)
  337. {
  338. return submit_test("/foo", 0, "/foo", 0, 0);
  339. }
  340. static int if_under_infinite(void)
  341. {
  342. return submit_test("/foo", NE_DEPTH_INFINITE, "/foo/bar", 0, 0);
  343. }
  344. static int if_infinite_over(void)
  345. {
  346. return submit_test("/foo/bar", 0, "/foo/", NE_DEPTH_INFINITE, 0);
  347. }
  348. static int if_child(void)
  349. {
  350. return submit_test("/foo/", 0, "/foo/bar", 0, LOCK_MODPARENT);
  351. }
  352. /* this is a special test, where the PARENT resource of "/foo/bar" is
  353. * modified, but NOT "/foo/bar" itself. An UNLOCK request on a
  354. * lock-null resource can do this; see ne_unlock() for the comment.
  355. * Regression test for neon <= 0.19.3, which didn't handle this
  356. * correctly. */
  357. static int if_covered_child(void)
  358. {
  359. return submit_test("/", NE_DEPTH_INFINITE, "/foo/bar", -1,
  360. LOCK_MODPARENT);
  361. }
  362. static int if_sharepoint(void)
  363. {
  364. return submit_test("/foo-sharepoint", 0, "/foo-sharepoint", 0,
  365. LOCK_SHAREPOINT);
  366. }
  367. static int if_movefrom(void)
  368. {
  369. return submit_test2("/from", 0, "/from/here.txt", "/to", 0, LOCK_MOVE);
  370. }
  371. static int serve_discovery(ne_socket *sock, void *userdata)
  372. {
  373. char buf[BUFSIZ], *resp = userdata;
  374. ON(discard_request(sock));
  375. ONN("no PROPFIND body", clength == 0);
  376. ON(ne_sock_read(sock, buf, clength) < 0);
  377. ON(SEND_STRING(sock, "HTTP/1.0 207 OK" EOL
  378. "Connection: close" EOL EOL));
  379. ON(SEND_STRING(sock, resp));
  380. return OK;
  381. }
  382. struct result_args {
  383. struct ne_lock *lock;
  384. ne_uri uri;
  385. int result;
  386. };
  387. static int lock_compare(const char *ctx,
  388. const struct ne_lock *a, const struct ne_lock *b)
  389. {
  390. ONV(!a->uri.host || !a->uri.scheme || !a->uri.path,
  391. ("URI structure incomplete in %s", ctx));
  392. ONV(ne_uri_cmp(&a->uri, &b->uri) != 0,
  393. ("URI comparison failed for %s: %s not %s", ctx,
  394. ne_uri_unparse(&a->uri), ne_uri_unparse(&b->uri)));
  395. ONV(a->depth != b->depth,
  396. ("%s depth was %d not %d", ctx, a->depth, b->depth));
  397. ONV(a->scope != b->scope,
  398. ("%s scope was %d not %d", ctx, a->scope, b->scope));
  399. ONV(a->type != b->type,
  400. ("%s type was %d not %d", ctx, a->type, b->type));
  401. return OK;
  402. }
  403. static void discover_result(void *userdata, const struct ne_lock *lk,
  404. const ne_uri *uri, const ne_status *st)
  405. {
  406. struct result_args *args = userdata;
  407. if (ne_uri_cmp(uri, &args->uri) != 0) {
  408. NE_DEBUG(NE_DBG_HTTP, "discover: URI mismatch: %s not %s",
  409. ne_uri_unparse(uri), ne_uri_unparse(&args->uri));
  410. args->result = FAIL;
  411. }
  412. else {
  413. NE_DEBUG(NE_DBG_HTTP, "test: Comparing discovered lock [%s] for %s "
  414. "with expected [%s]...\n",
  415. lk->token, uri->path, args->lock->token);
  416. args->result = lock_compare("discovered lock", lk, args->lock);
  417. }
  418. }
  419. static int discover(void)
  420. {
  421. ne_session *sess;
  422. char *response;
  423. int ret;
  424. struct result_args args;
  425. memset(&args, 0, sizeof args);
  426. args.lock = ne_lock_create();
  427. args.lock->owner = ne_strdup("someowner");
  428. args.lock->token = ne_strdup("sometoken");
  429. args.lock->uri.host = ne_strdup("localhost");
  430. args.lock->uri.port = 7777;
  431. args.lock->uri.scheme = ne_strdup("http");
  432. args.lock->uri.path = ne_strdup("/this/is/the/lock/path");
  433. /* default */
  434. args.result = FAIL;
  435. t_context("results callback never invoked");
  436. response = discover_response("/lockme", args.lock);
  437. CALL(fake_session(&sess, serve_discovery, response));
  438. ne_free(response);
  439. ne_fill_server_uri(sess, &args.uri);
  440. args.uri.path = ne_strdup("/lockme");
  441. ret = ne_lock_discover(sess, "/lockme", discover_result, &args);
  442. CALL(await_server());
  443. ONREQ(ret);
  444. ne_lock_destroy(args.lock);
  445. ne_uri_free(&args.uri);
  446. ne_session_destroy(sess);
  447. return args.result;
  448. }
  449. /* Check that the token for the response header */
  450. static int lock_shared(void)
  451. {
  452. ne_session *sess;
  453. char *resp, *rbody;
  454. struct ne_lock *lock, *resplocks[3];
  455. #define FILLK(l, s) do { \
  456. (l)->token = strdup("opaquelocktoken:" s); \
  457. (l)->owner = strdup("owner " s); \
  458. (l)->uri.path = strdup("/" s); (l)->uri.host = strdup("localhost"); \
  459. (l)->uri.scheme = strdup("http"); (l)->uri.port = 7777; } while (0)
  460. resplocks[0] = ne_lock_create();
  461. resplocks[1] = ne_lock_create();
  462. resplocks[2] = NULL;
  463. FILLK(resplocks[0], "alpha");
  464. FILLK(resplocks[1], "beta");
  465. resplocks[0]->timeout = 100;
  466. resplocks[1]->timeout = 200;
  467. rbody = multi_lock_response(resplocks);
  468. resp = ne_concat("HTTP/1.1 200 OK\r\n" "Server: neon-test-server\r\n"
  469. "Content-type: application/xml" EOL
  470. "Lock-Token: <opaquelocktoken:beta>" EOL
  471. "Connection: close\r\n\r\n", rbody, NULL);
  472. ne_free(rbody);
  473. CALL(fake_session(&sess, single_serve_string, resp));
  474. ne_free(resp);
  475. lock = ne_lock_create();
  476. ne_fill_server_uri(sess, &lock->uri);
  477. lock->uri.path = ne_strdup("/beta");
  478. ONREQ(ne_lock(sess, lock));
  479. CALL(await_server());
  480. CALL(lock_compare("returned lock", resplocks[1], lock));
  481. ne_session_destroy(sess);
  482. ne_lock_destroy(lock);
  483. ne_lock_destroy(resplocks[0]);
  484. ne_lock_destroy(resplocks[1]);
  485. return OK;
  486. }
  487. static void dummy_discover(void *userdata, const struct ne_lock *lock,
  488. const ne_uri *uri, const ne_status *status)
  489. {
  490. }
  491. /* This failed with neon 0.25.x and earlier when memory leak detection
  492. * is enabled. */
  493. static int fail_discover(void)
  494. {
  495. ne_session *sess;
  496. int ret;
  497. CALL(fake_session(&sess, single_serve_string,
  498. "HTTP/1.0 207 OK\r\n" "Connection: close\r\n" "\r\n"
  499. "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
  500. "<D:multistatus xmlns:D='DAV:'>\n"
  501. "<D:response><D:href>/foo/bar</D:href><D:propstat>\n"
  502. "</parse this, my friend>\n"));
  503. ret = ne_lock_discover(sess, "/foo", dummy_discover, NULL);
  504. ONN("discovery okay for response with invalid XML!?", ret != NE_ERROR);
  505. return destroy_and_wait(sess);
  506. }
  507. static int no_creds(void *ud, const char *realm, int attempt,
  508. char *username, char *password)
  509. {
  510. return -1;
  511. }
  512. static int fail_lockauth(void)
  513. {
  514. ne_session *sess;
  515. struct ne_lock *lock;
  516. int ret;
  517. struct many_serve_args args;
  518. args.str = "HTTP/1.1 401 Auth Denied\r\n"
  519. "WWW-Authenticate: Basic realm=\"realm@host\"\r\n"
  520. "Content-Length: 0\r\n"
  521. "\r\n";
  522. args.count = 2;
  523. CALL(fake_session(&sess, many_serve_string, &args));
  524. ne_set_server_auth(sess, no_creds, NULL);
  525. lock = make_lock("/foo", NULL, ne_lockscope_exclusive, NE_DEPTH_ZERO);
  526. ret = ne_lock(sess, lock);
  527. ONV(ret != NE_AUTH,
  528. ("attempt to lock did not fail with NE_AUTH: %d (%s)",
  529. ret, ne_get_error(sess)));
  530. ne_lock_destroy(lock);
  531. lock = make_lock("/bar", "fish", ne_lockscope_exclusive, NE_DEPTH_ZERO);
  532. lock->token = ne_strdup("opaquelocktoken:gah");
  533. ret = ne_unlock(sess, lock);
  534. ONV(ret != NE_AUTH,
  535. ("attempt to unlock did not fail with NE_AUTH: %d (%s)",
  536. ret, ne_get_error(sess)));
  537. ne_lock_destroy(lock);
  538. return destroy_and_wait(sess);
  539. }
  540. /* Regression test for neon 0.25.0 regression in ne_lock() error
  541. * handling. */
  542. static int fail_noheader(void)
  543. {
  544. ne_session *sess;
  545. char *resp, *rbody = lock_response(ne_lockscope_exclusive, 0, "me",
  546. FOO_LOCKROOT, 6500, "opaquelocktoken:foo");
  547. struct ne_lock *lock = ne_lock_create();
  548. int ret;
  549. resp = ne_concat("HTTP/1.1 200 OK\r\n" "Server: neon-test-server\r\n"
  550. "Content-type: application/xml" EOL
  551. "Connection: close\r\n\r\n", rbody, NULL);
  552. CALL(fake_session(&sess, single_serve_string, resp));
  553. ne_free(resp);
  554. ne_fill_server_uri(sess, &lock->uri);
  555. lock->uri.path = ne_strdup("/foo");
  556. lock->timeout = NE_TIMEOUT_INFINITE;
  557. ret = ne_lock(sess, lock);
  558. ONN("LOCK request did not fail", ret != NE_ERROR);
  559. ONV(strstr(ne_get_error(sess),
  560. "LOCK response missing Lock-Token header") == NULL,
  561. ("unexpected error: %s", ne_get_error(sess)));
  562. ne_session_destroy(sess);
  563. ne_lock_destroy(lock);
  564. return await_server();
  565. }
  566. ne_test tests[] = {
  567. T(lookup_localhost),
  568. T(store_single),
  569. T(store_several),
  570. T(if_simple),
  571. T(if_under_infinite),
  572. T(if_infinite_over),
  573. T(if_child),
  574. T(if_covered_child),
  575. T(if_sharepoint),
  576. T(if_movefrom),
  577. T(lock_timeout),
  578. T(lock_long_timeout),
  579. T(lock_shared),
  580. T(discover),
  581. T(fail_discover),
  582. T(fail_lockauth),
  583. T(fail_noheader),
  584. T(NULL)
  585. };