chore: add CMake test infrastructure and placeholder unit test files for future coverage
This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
#include "../../test_framework.h"
|
||||
#include "../http_endpoints.h"
|
||||
|
||||
TEST_SUITE(auth_401_challenge)
|
||||
|
||||
TEST(no_auth_header_returns_401) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/protected.txt", "secret", 6);
|
||||
|
||||
endpoint_test_execute(ctx, "GET", "/protected.txt", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_401_UNAUTHORIZED, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(401_includes_www_authenticate_header) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/protected.txt", "secret", 6);
|
||||
|
||||
endpoint_test_execute(ctx, "GET", "/protected.txt", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_401_UNAUTHORIZED, ctx->response.status);
|
||||
ASSERT_TRUE(endpoint_response_has_header(ctx, "WWW-Authenticate", NULL));
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(401_challenge_includes_realm) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/file.txt", "x", 1);
|
||||
|
||||
endpoint_test_execute(ctx, "GET", "/file.txt", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_401_UNAUTHORIZED, ctx->response.status);
|
||||
const char *www_auth = endpoint_response_get_header(ctx, "WWW-Authenticate");
|
||||
ASSERT_NOT_NULL(www_auth);
|
||||
ASSERT_TRUE(strstr(www_auth, "realm=") != NULL);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(401_for_put_without_auth) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
endpoint_test_execute(ctx, "PUT", "/newfile.txt", "content", 7);
|
||||
|
||||
ASSERT_EQUAL(HTTP_401_UNAUTHORIZED, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(401_for_delete_without_auth) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/file.txt", "x", 1);
|
||||
|
||||
endpoint_test_execute(ctx, "DELETE", "/file.txt", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_401_UNAUTHORIZED, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(401_for_mkcol_without_auth) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
endpoint_test_execute(ctx, "MKCOL", "/newfolder", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_401_UNAUTHORIZED, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(401_for_proppatch_without_auth) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/file.txt", "x", 1);
|
||||
|
||||
const char *body =
|
||||
"<?xml version=\"1.0\"?>"
|
||||
"<propertyupdate xmlns=\"DAV:\">"
|
||||
"<set><prop><displayname>x</displayname></prop></set>"
|
||||
"</propertyupdate>";
|
||||
|
||||
endpoint_test_execute(ctx, "PROPPATCH", "/file.txt", body, strlen(body));
|
||||
|
||||
ASSERT_EQUAL(HTTP_401_UNAUTHORIZED, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(malformed_auth_header_returns_401) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/file.txt", "x", 1);
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "GET", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/file.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Authorization", "InvalidScheme xyz123");
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_401_UNAUTHORIZED, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(empty_auth_header_returns_401) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/file.txt", "x", 1);
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "GET", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/file.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Authorization", "");
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_401_UNAUTHORIZED, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(options_allowed_without_auth) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
endpoint_test_execute(ctx, "OPTIONS", "/", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_200_OK, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
#include "../../test_framework.h"
|
||||
#include "../http_endpoints.h"
|
||||
|
||||
TEST_SUITE(auth_basic_flow)
|
||||
|
||||
TEST(basic_auth_valid_credentials) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
user_manager_add(ctx->fixture->user_mgr, "testuser", "testpass",
|
||||
"test@example.com", 0);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/protected.txt", "secret", 6);
|
||||
|
||||
endpoint_test_execute_with_auth(ctx, "GET", "/protected.txt",
|
||||
"testuser", "testpass", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_200_OK, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(basic_auth_invalid_password) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
user_manager_add(ctx->fixture->user_mgr, "testuser", "correctpass",
|
||||
"test@example.com", 0);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/protected.txt", "secret", 6);
|
||||
|
||||
endpoint_test_execute_with_auth(ctx, "GET", "/protected.txt",
|
||||
"testuser", "wrongpass", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_401_UNAUTHORIZED, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(basic_auth_unknown_user) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/protected.txt", "secret", 6);
|
||||
|
||||
endpoint_test_execute_with_auth(ctx, "GET", "/protected.txt",
|
||||
"unknown", "anypass", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_401_UNAUTHORIZED, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(basic_auth_disabled_user) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
user_manager_add(ctx->fixture->user_mgr, "disabled", "password",
|
||||
"disabled@example.com", 0);
|
||||
user_manager_enable(ctx->fixture->user_mgr, "disabled", 0);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/protected.txt", "secret", 6);
|
||||
|
||||
endpoint_test_execute_with_auth(ctx, "GET", "/protected.txt",
|
||||
"disabled", "password", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_401_UNAUTHORIZED, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(basic_auth_put_file) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
user_manager_add(ctx->fixture->user_mgr, "writer", "writepass",
|
||||
"writer@example.com", 0);
|
||||
|
||||
const char *content = "new file content";
|
||||
endpoint_test_execute_with_auth(ctx, "PUT", "/newfile.txt",
|
||||
"writer", "writepass",
|
||||
content, strlen(content));
|
||||
|
||||
ASSERT_EQUAL(HTTP_201_CREATED, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(basic_auth_mkcol) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
user_manager_add(ctx->fixture->user_mgr, "creator", "createpass",
|
||||
"creator@example.com", 0);
|
||||
|
||||
endpoint_test_execute_with_auth(ctx, "MKCOL", "/newfolder",
|
||||
"creator", "createpass", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_201_CREATED, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(basic_auth_delete) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
user_manager_add(ctx->fixture->user_mgr, "deleter", "deletepass",
|
||||
"deleter@example.com", 0);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/todelete.txt", "x", 1);
|
||||
|
||||
endpoint_test_execute_with_auth(ctx, "DELETE", "/todelete.txt",
|
||||
"deleter", "deletepass", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_204_NO_CONTENT, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(basic_auth_special_chars_in_password) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
user_manager_add(ctx->fixture->user_mgr, "special", "p@ss:w0rd!#$",
|
||||
"special@example.com", 0);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/file.txt", "x", 1);
|
||||
|
||||
endpoint_test_execute_with_auth(ctx, "GET", "/file.txt",
|
||||
"special", "p@ss:w0rd!#$", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_200_OK, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
#include "../../test_framework.h"
|
||||
#include "../http_endpoints.h"
|
||||
#include "../../src/auth/auth.h"
|
||||
|
||||
TEST_SUITE(auth_digest_flow)
|
||||
|
||||
static void compute_digest_response(const char *username, const char *password,
|
||||
const char *realm, const char *nonce,
|
||||
const char *method, const char *uri,
|
||||
const char *nc, const char *cnonce,
|
||||
const char *qop, char *out_response) {
|
||||
char ha1[65], ha2[65];
|
||||
|
||||
char a1[512];
|
||||
snprintf(a1, sizeof(a1), "%s:%s:%s", username, realm, password);
|
||||
auth_md5_hex(a1, strlen(a1), ha1);
|
||||
|
||||
char a2[512];
|
||||
snprintf(a2, sizeof(a2), "%s:%s", method, uri);
|
||||
auth_md5_hex(a2, strlen(a2), ha2);
|
||||
|
||||
char response_str[1024];
|
||||
snprintf(response_str, sizeof(response_str), "%s:%s:%s:%s:%s:%s",
|
||||
ha1, nonce, nc, cnonce, qop, ha2);
|
||||
auth_md5_hex(response_str, strlen(response_str), out_response);
|
||||
}
|
||||
|
||||
TEST(digest_auth_valid_credentials) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
user_manager_add(ctx->fixture->user_mgr, "digestuser", "digestpass",
|
||||
"digest@example.com", 0);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/secure.txt", "secret data", 11);
|
||||
|
||||
const char *realm = "WebDAV";
|
||||
const char *nonce = "abc123nonce";
|
||||
const char *uri = "/secure.txt";
|
||||
const char *nc = "00000001";
|
||||
const char *cnonce = "xyz789cnonce";
|
||||
const char *qop = "auth";
|
||||
|
||||
char response[65];
|
||||
compute_digest_response("digestuser", "digestpass", realm, nonce,
|
||||
"GET", uri, nc, cnonce, qop, response);
|
||||
|
||||
char auth_header[1024];
|
||||
snprintf(auth_header, sizeof(auth_header),
|
||||
"Digest username=\"digestuser\", realm=\"%s\", nonce=\"%s\", "
|
||||
"uri=\"%s\", nc=%s, cnonce=\"%s\", qop=%s, response=\"%s\"",
|
||||
realm, nonce, uri, nc, cnonce, qop, response);
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "GET", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, uri, sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Authorization", auth_header);
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_200_OK, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(digest_auth_invalid_response) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
user_manager_add(ctx->fixture->user_mgr, "testuser", "testpass",
|
||||
"test@example.com", 0);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/file.txt", "data", 4);
|
||||
|
||||
char auth_header[1024];
|
||||
snprintf(auth_header, sizeof(auth_header),
|
||||
"Digest username=\"testuser\", realm=\"WebDAV\", nonce=\"abc123\", "
|
||||
"uri=\"/file.txt\", nc=00000001, cnonce=\"xyz789\", qop=auth, "
|
||||
"response=\"invalidresponse\"");
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "GET", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/file.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Authorization", auth_header);
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_401_UNAUTHORIZED, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(digest_auth_unknown_user) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/file.txt", "data", 4);
|
||||
|
||||
char response[65];
|
||||
compute_digest_response("unknown", "anypass", "WebDAV", "nonce123",
|
||||
"GET", "/file.txt", "00000001", "cnonce", "auth", response);
|
||||
|
||||
char auth_header[1024];
|
||||
snprintf(auth_header, sizeof(auth_header),
|
||||
"Digest username=\"unknown\", realm=\"WebDAV\", nonce=\"nonce123\", "
|
||||
"uri=\"/file.txt\", nc=00000001, cnonce=\"cnonce\", qop=auth, "
|
||||
"response=\"%s\"", response);
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "GET", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/file.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Authorization", auth_header);
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_401_UNAUTHORIZED, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(digest_auth_put_operation) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
user_manager_add(ctx->fixture->user_mgr, "writer", "writepass",
|
||||
"writer@example.com", 0);
|
||||
|
||||
const char *realm = "WebDAV";
|
||||
const char *nonce = "putnonce";
|
||||
const char *uri = "/newfile.txt";
|
||||
const char *nc = "00000001";
|
||||
const char *cnonce = "putcnonce";
|
||||
const char *qop = "auth";
|
||||
|
||||
char response[65];
|
||||
compute_digest_response("writer", "writepass", realm, nonce,
|
||||
"PUT", uri, nc, cnonce, qop, response);
|
||||
|
||||
char auth_header[1024];
|
||||
snprintf(auth_header, sizeof(auth_header),
|
||||
"Digest username=\"writer\", realm=\"%s\", nonce=\"%s\", "
|
||||
"uri=\"%s\", nc=%s, cnonce=\"%s\", qop=%s, response=\"%s\"",
|
||||
realm, nonce, uri, nc, cnonce, qop, response);
|
||||
|
||||
const char *content = "file content";
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "PUT", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, uri, sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Authorization", auth_header);
|
||||
ctx->request.body = strdup(content);
|
||||
ctx->request.body_len = strlen(content);
|
||||
ctx->request.content_length = strlen(content);
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_201_CREATED, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
#ifndef HTTP_ENDPOINTS_H
|
||||
#define HTTP_ENDPOINTS_H
|
||||
|
||||
#include "../fixtures/fixtures.h"
|
||||
#include "../fixtures/http_request_builder.h"
|
||||
#include "../../src/http/request.h"
|
||||
#include "../../src/http/response.h"
|
||||
#include "../../src/webdav/handler.h"
|
||||
|
||||
typedef struct {
|
||||
test_fixture_t *fixture;
|
||||
http_request_t request;
|
||||
http_response_t response;
|
||||
char *raw_request;
|
||||
} endpoint_test_ctx_t;
|
||||
|
||||
static inline endpoint_test_ctx_t *endpoint_test_create(void) {
|
||||
endpoint_test_ctx_t *ctx = calloc(1, sizeof(endpoint_test_ctx_t));
|
||||
if (!ctx) return NULL;
|
||||
|
||||
ctx->fixture = fixture_create_with_storage();
|
||||
if (!ctx->fixture) {
|
||||
free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
http_response_init(&ctx->response);
|
||||
ctx->raw_request = NULL;
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
static inline void endpoint_test_destroy(endpoint_test_ctx_t *ctx) {
|
||||
if (!ctx) return;
|
||||
|
||||
http_request_free(&ctx->request);
|
||||
http_response_free(&ctx->response);
|
||||
if (ctx->raw_request) free(ctx->raw_request);
|
||||
fixture_destroy(ctx->fixture);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
static inline int endpoint_test_execute(endpoint_test_ctx_t *ctx,
|
||||
const char *method,
|
||||
const char *path,
|
||||
const char *body,
|
||||
size_t body_len) {
|
||||
http_request_free(&ctx->request);
|
||||
http_request_init(&ctx->request);
|
||||
|
||||
strncpy(ctx->request.method, method, sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, path, sizeof(ctx->request.uri) - 1);
|
||||
strncpy(ctx->request.version, "HTTP/1.1", sizeof(ctx->request.version) - 1);
|
||||
|
||||
if (body && body_len > 0) {
|
||||
ctx->request.body = malloc(body_len + 1);
|
||||
if (ctx->request.body) {
|
||||
memcpy(ctx->request.body, body, body_len);
|
||||
ctx->request.body[body_len] = '\0';
|
||||
ctx->request.body_len = body_len;
|
||||
ctx->request.content_length = body_len;
|
||||
}
|
||||
}
|
||||
|
||||
http_response_free(&ctx->response);
|
||||
http_response_init(&ctx->response);
|
||||
|
||||
return webdav_handle_request(ctx->fixture->storage,
|
||||
ctx->fixture->locks,
|
||||
ctx->fixture->props,
|
||||
&ctx->request,
|
||||
&ctx->response);
|
||||
}
|
||||
|
||||
static inline int endpoint_test_execute_with_auth(endpoint_test_ctx_t *ctx,
|
||||
const char *method,
|
||||
const char *path,
|
||||
const char *username,
|
||||
const char *password,
|
||||
const char *body,
|
||||
size_t body_len) {
|
||||
http_request_free(&ctx->request);
|
||||
http_request_init(&ctx->request);
|
||||
|
||||
strncpy(ctx->request.method, method, sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, path, sizeof(ctx->request.uri) - 1);
|
||||
strncpy(ctx->request.version, "HTTP/1.1", sizeof(ctx->request.version) - 1);
|
||||
|
||||
if (username && password) {
|
||||
char credentials[256];
|
||||
snprintf(credentials, sizeof(credentials), "%s:%s", username, password);
|
||||
char *encoded = auth_base64_encode((unsigned char *)credentials, strlen(credentials));
|
||||
if (encoded) {
|
||||
char auth_header[512];
|
||||
snprintf(auth_header, sizeof(auth_header), "Basic %s", encoded);
|
||||
http_request_add_header(&ctx->request, "Authorization", auth_header);
|
||||
free(encoded);
|
||||
}
|
||||
}
|
||||
|
||||
if (body && body_len > 0) {
|
||||
ctx->request.body = malloc(body_len + 1);
|
||||
if (ctx->request.body) {
|
||||
memcpy(ctx->request.body, body, body_len);
|
||||
ctx->request.body[body_len] = '\0';
|
||||
ctx->request.body_len = body_len;
|
||||
ctx->request.content_length = body_len;
|
||||
}
|
||||
}
|
||||
|
||||
http_response_free(&ctx->response);
|
||||
http_response_init(&ctx->response);
|
||||
|
||||
return webdav_handle_request(ctx->fixture->storage,
|
||||
ctx->fixture->locks,
|
||||
ctx->fixture->props,
|
||||
&ctx->request,
|
||||
&ctx->response);
|
||||
}
|
||||
|
||||
static inline void endpoint_test_add_header(endpoint_test_ctx_t *ctx,
|
||||
const char *name,
|
||||
const char *value) {
|
||||
http_request_add_header(&ctx->request, name, value);
|
||||
}
|
||||
|
||||
static inline int endpoint_response_has_header(endpoint_test_ctx_t *ctx,
|
||||
const char *name,
|
||||
const char *expected_value) {
|
||||
response_header_t *h = ctx->response.headers;
|
||||
while (h) {
|
||||
if (strcasecmp(h->name, name) == 0) {
|
||||
if (expected_value == NULL) return 1;
|
||||
return strcmp(h->value, expected_value) == 0;
|
||||
}
|
||||
h = h->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline const char *endpoint_response_get_header(endpoint_test_ctx_t *ctx,
|
||||
const char *name) {
|
||||
response_header_t *h = ctx->response.headers;
|
||||
while (h) {
|
||||
if (strcasecmp(h->name, name) == 0) {
|
||||
return h->value;
|
||||
}
|
||||
h = h->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,116 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
#include "../../test_framework.h"
|
||||
#include "../http_endpoints.h"
|
||||
|
||||
TEST_SUITE(http_head)
|
||||
|
||||
TEST(head_existing_file) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
const char *content = "Test content for HEAD";
|
||||
storage_write_file(ctx->fixture->storage, "/test.txt", content, strlen(content));
|
||||
|
||||
endpoint_test_execute(ctx, "HEAD", "/test.txt", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_200_OK, ctx->response.status);
|
||||
ASSERT_TRUE(ctx->response.body == NULL || ctx->response.body_len == 0);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(head_includes_content_length) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
const char *content = "exactly 25 bytes of data!";
|
||||
storage_write_file(ctx->fixture->storage, "/sized.txt", content, strlen(content));
|
||||
|
||||
endpoint_test_execute(ctx, "HEAD", "/sized.txt", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_200_OK, ctx->response.status);
|
||||
const char *cl = endpoint_response_get_header(ctx, "Content-Length");
|
||||
ASSERT_NOT_NULL(cl);
|
||||
ASSERT_EQUAL(25, atoi(cl));
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(head_includes_content_type) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/page.html", "<html></html>", 13);
|
||||
|
||||
endpoint_test_execute(ctx, "HEAD", "/page.html", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_200_OK, ctx->response.status);
|
||||
ASSERT_TRUE(endpoint_response_has_header(ctx, "Content-Type", NULL));
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(head_not_found) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
endpoint_test_execute(ctx, "HEAD", "/nonexistent.txt", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_404_NOT_FOUND, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(head_collection) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_create_collection(ctx->fixture->storage, "/folder");
|
||||
|
||||
endpoint_test_execute(ctx, "HEAD", "/folder", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_200_OK, ctx->response.status);
|
||||
ASSERT_TRUE(ctx->response.body == NULL || ctx->response.body_len == 0);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(head_root) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
endpoint_test_execute(ctx, "HEAD", "/", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_200_OK, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(head_includes_etag) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/etag.txt", "content", 7);
|
||||
|
||||
endpoint_test_execute(ctx, "HEAD", "/etag.txt", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_200_OK, ctx->response.status);
|
||||
ASSERT_TRUE(endpoint_response_has_header(ctx, "ETag", NULL));
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(head_includes_last_modified) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/modified.txt", "data", 4);
|
||||
|
||||
endpoint_test_execute(ctx, "HEAD", "/modified.txt", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_200_OK, ctx->response.status);
|
||||
ASSERT_TRUE(endpoint_response_has_header(ctx, "Last-Modified", NULL));
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
#include "../../test_framework.h"
|
||||
#include "../http_endpoints.h"
|
||||
|
||||
TEST_SUITE(http_post)
|
||||
|
||||
TEST(post_not_implemented) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
endpoint_test_execute(ctx, "POST", "/", "data=test", 9);
|
||||
|
||||
ASSERT_TRUE(ctx->response.status == HTTP_405_METHOD_NOT_ALLOWED ||
|
||||
ctx->response.status == HTTP_501_NOT_IMPLEMENTED);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(post_to_file) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/file.txt", "content", 7);
|
||||
|
||||
endpoint_test_execute(ctx, "POST", "/file.txt", "posted=data", 11);
|
||||
|
||||
ASSERT_TRUE(ctx->response.status == HTTP_405_METHOD_NOT_ALLOWED ||
|
||||
ctx->response.status == HTTP_501_NOT_IMPLEMENTED);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(post_to_collection) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_create_collection(ctx->fixture->storage, "/folder");
|
||||
|
||||
endpoint_test_execute(ctx, "POST", "/folder", "data", 4);
|
||||
|
||||
ASSERT_TRUE(ctx->response.status == HTTP_405_METHOD_NOT_ALLOWED ||
|
||||
ctx->response.status == HTTP_501_NOT_IMPLEMENTED);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(post_with_content_type) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "POST", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Content-Type", "application/x-www-form-urlencoded");
|
||||
ctx->request.body = strdup("key=value");
|
||||
ctx->request.body_len = 9;
|
||||
ctx->request.content_length = 9;
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_TRUE(ctx->response.status == HTTP_405_METHOD_NOT_ALLOWED ||
|
||||
ctx->response.status == HTTP_501_NOT_IMPLEMENTED);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(post_empty_body) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
endpoint_test_execute(ctx, "POST", "/", NULL, 0);
|
||||
|
||||
ASSERT_TRUE(ctx->response.status == HTTP_405_METHOD_NOT_ALLOWED ||
|
||||
ctx->response.status == HTTP_501_NOT_IMPLEMENTED);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
#include "../../test_framework.h"
|
||||
#include "../http_endpoints.h"
|
||||
|
||||
TEST_SUITE(webdav_copy)
|
||||
|
||||
TEST(copy_file) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
const char *content = "original content";
|
||||
storage_write_file(ctx->fixture->storage, "/source.txt", content, strlen(content));
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "COPY", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/source.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Destination", "/dest.txt");
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_201_CREATED, ctx->response.status);
|
||||
|
||||
int exists = storage_exists(ctx->fixture->storage, "/dest.txt");
|
||||
ASSERT_TRUE(exists);
|
||||
|
||||
exists = storage_exists(ctx->fixture->storage, "/source.txt");
|
||||
ASSERT_TRUE(exists);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(copy_collection) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_create_collection(ctx->fixture->storage, "/srcfolder");
|
||||
storage_write_file(ctx->fixture->storage, "/srcfolder/file1.txt", "a", 1);
|
||||
storage_write_file(ctx->fixture->storage, "/srcfolder/file2.txt", "b", 1);
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "COPY", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/srcfolder", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Destination", "/dstfolder");
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_201_CREATED, ctx->response.status);
|
||||
|
||||
int exists = storage_exists(ctx->fixture->storage, "/dstfolder");
|
||||
ASSERT_TRUE(exists);
|
||||
exists = storage_exists(ctx->fixture->storage, "/dstfolder/file1.txt");
|
||||
ASSERT_TRUE(exists);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(copy_source_not_found) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "COPY", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/nonexistent.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Destination", "/dest.txt");
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_404_NOT_FOUND, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(copy_missing_destination_header) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/source.txt", "data", 4);
|
||||
|
||||
endpoint_test_execute(ctx, "COPY", "/source.txt", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_400_BAD_REQUEST, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(copy_overwrite_true) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/src.txt", "source", 6);
|
||||
storage_write_file(ctx->fixture->storage, "/dst.txt", "destination", 11);
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "COPY", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/src.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Destination", "/dst.txt");
|
||||
http_request_add_header(&ctx->request, "Overwrite", "T");
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_204_NO_CONTENT, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(copy_overwrite_false_fails) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/src.txt", "source", 6);
|
||||
storage_write_file(ctx->fixture->storage, "/dst.txt", "destination", 11);
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "COPY", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/src.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Destination", "/dst.txt");
|
||||
http_request_add_header(&ctx->request, "Overwrite", "F");
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_412_PRECONDITION_FAILED, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(copy_dest_parent_missing) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/src.txt", "data", 4);
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "COPY", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/src.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Destination", "/missing/dst.txt");
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_409_CONFLICT, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
#include "../../test_framework.h"
|
||||
#include "../http_endpoints.h"
|
||||
|
||||
TEST_SUITE(webdav_delete)
|
||||
|
||||
TEST(delete_file) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/todelete.txt", "content", 7);
|
||||
|
||||
endpoint_test_execute(ctx, "DELETE", "/todelete.txt", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_204_NO_CONTENT, ctx->response.status);
|
||||
|
||||
int exists = storage_exists(ctx->fixture->storage, "/todelete.txt");
|
||||
ASSERT_FALSE(exists);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(delete_empty_collection) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_create_collection(ctx->fixture->storage, "/emptyfolder");
|
||||
|
||||
endpoint_test_execute(ctx, "DELETE", "/emptyfolder", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_204_NO_CONTENT, ctx->response.status);
|
||||
|
||||
int exists = storage_exists(ctx->fixture->storage, "/emptyfolder");
|
||||
ASSERT_FALSE(exists);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(delete_collection_with_contents) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_create_collection(ctx->fixture->storage, "/folder");
|
||||
storage_write_file(ctx->fixture->storage, "/folder/file1.txt", "a", 1);
|
||||
storage_write_file(ctx->fixture->storage, "/folder/file2.txt", "b", 1);
|
||||
storage_create_collection(ctx->fixture->storage, "/folder/sub");
|
||||
storage_write_file(ctx->fixture->storage, "/folder/sub/deep.txt", "c", 1);
|
||||
|
||||
endpoint_test_execute(ctx, "DELETE", "/folder", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_204_NO_CONTENT, ctx->response.status);
|
||||
|
||||
int exists = storage_exists(ctx->fixture->storage, "/folder");
|
||||
ASSERT_FALSE(exists);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(delete_nonexistent_returns_404) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
endpoint_test_execute(ctx, "DELETE", "/doesnotexist.txt", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_404_NOT_FOUND, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(delete_root_not_allowed) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
endpoint_test_execute(ctx, "DELETE", "/", NULL, 0);
|
||||
|
||||
ASSERT_NOT_EQUAL(HTTP_204_NO_CONTENT, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(delete_locked_resource_fails) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/locked.txt", "data", 4);
|
||||
|
||||
lock_info_t lock;
|
||||
memset(&lock, 0, sizeof(lock));
|
||||
strncpy(lock.owner, "user1", sizeof(lock.owner) - 1);
|
||||
lock.scope = LOCK_SCOPE_EXCLUSIVE;
|
||||
lock.type = LOCK_TYPE_WRITE;
|
||||
lock.timeout = 3600;
|
||||
lock_manager_acquire(ctx->fixture->locks, "/locked.txt", &lock);
|
||||
|
||||
endpoint_test_execute(ctx, "DELETE", "/locked.txt", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_423_LOCKED, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(delete_with_valid_lock_token) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/locked2.txt", "data", 4);
|
||||
|
||||
lock_info_t lock;
|
||||
memset(&lock, 0, sizeof(lock));
|
||||
strncpy(lock.owner, "user1", sizeof(lock.owner) - 1);
|
||||
lock.scope = LOCK_SCOPE_EXCLUSIVE;
|
||||
lock.type = LOCK_TYPE_WRITE;
|
||||
lock.timeout = 3600;
|
||||
lock_manager_acquire(ctx->fixture->locks, "/locked2.txt", &lock);
|
||||
|
||||
char if_header[256];
|
||||
snprintf(if_header, sizeof(if_header), "(<%s>)", lock.token);
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "DELETE", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/locked2.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "If", if_header);
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_204_NO_CONTENT, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
#include "../../test_framework.h"
|
||||
#include "../http_endpoints.h"
|
||||
|
||||
TEST_SUITE(webdav_get)
|
||||
|
||||
TEST(get_existing_file) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
const char *content = "Hello, World!";
|
||||
storage_write_file(ctx->fixture->storage, "/hello.txt", content, strlen(content));
|
||||
|
||||
endpoint_test_execute(ctx, "GET", "/hello.txt", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_200_OK, ctx->response.status);
|
||||
ASSERT_NOT_NULL(ctx->response.body);
|
||||
ASSERT_EQUAL(strlen(content), ctx->response.body_len);
|
||||
ASSERT_MEM_EQ(content, ctx->response.body, strlen(content));
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(get_nonexistent_file) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
endpoint_test_execute(ctx, "GET", "/nonexistent.txt", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_404_NOT_FOUND, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(get_collection_returns_listing) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_create_collection(ctx->fixture->storage, "/folder");
|
||||
storage_write_file(ctx->fixture->storage, "/folder/file1.txt", "a", 1);
|
||||
storage_write_file(ctx->fixture->storage, "/folder/file2.txt", "b", 1);
|
||||
|
||||
endpoint_test_execute(ctx, "GET", "/folder/", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_200_OK, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(get_sets_content_type) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/test.html", "<html></html>", 13);
|
||||
|
||||
endpoint_test_execute(ctx, "GET", "/test.html", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_200_OK, ctx->response.status);
|
||||
ASSERT_TRUE(endpoint_response_has_header(ctx, "Content-Type", NULL));
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(get_sets_content_length) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
const char *content = "exact length test";
|
||||
storage_write_file(ctx->fixture->storage, "/length.txt", content, strlen(content));
|
||||
|
||||
endpoint_test_execute(ctx, "GET", "/length.txt", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_200_OK, ctx->response.status);
|
||||
const char *cl = endpoint_response_get_header(ctx, "Content-Length");
|
||||
ASSERT_NOT_NULL(cl);
|
||||
ASSERT_EQUAL((int)strlen(content), atoi(cl));
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(get_binary_file) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
unsigned char binary[] = {0x00, 0x01, 0x02, 0xFF, 0xFE, 0xFD};
|
||||
storage_write_file(ctx->fixture->storage, "/binary.bin", (char *)binary, sizeof(binary));
|
||||
|
||||
endpoint_test_execute(ctx, "GET", "/binary.bin", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_200_OK, ctx->response.status);
|
||||
ASSERT_EQUAL(sizeof(binary), ctx->response.body_len);
|
||||
ASSERT_MEM_EQ(binary, ctx->response.body, sizeof(binary));
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(get_empty_file) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/empty.txt", "", 0);
|
||||
|
||||
endpoint_test_execute(ctx, "GET", "/empty.txt", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_200_OK, ctx->response.status);
|
||||
ASSERT_EQUAL(0, ctx->response.body_len);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(get_root_collection) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
endpoint_test_execute(ctx, "GET", "/", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_200_OK, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(get_path_traversal_blocked) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
endpoint_test_execute(ctx, "GET", "/../etc/passwd", NULL, 0);
|
||||
|
||||
ASSERT_NOT_EQUAL(HTTP_200_OK, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
#include "../../test_framework.h"
|
||||
#include "../http_endpoints.h"
|
||||
|
||||
TEST_SUITE(webdav_lock)
|
||||
|
||||
TEST(lock_file_exclusive) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/file.txt", "content", 7);
|
||||
|
||||
const char *body =
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
"<lockinfo xmlns=\"DAV:\">"
|
||||
"<lockscope><exclusive/></lockscope>"
|
||||
"<locktype><write/></locktype>"
|
||||
"<owner><href>http://example.com/user</href></owner>"
|
||||
"</lockinfo>";
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "LOCK", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/file.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Content-Type", "application/xml");
|
||||
http_request_add_header(&ctx->request, "Timeout", "Second-3600");
|
||||
ctx->request.body = strdup(body);
|
||||
ctx->request.body_len = strlen(body);
|
||||
ctx->request.content_length = strlen(body);
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_200_OK, ctx->response.status);
|
||||
ASSERT_TRUE(endpoint_response_has_header(ctx, "Lock-Token", NULL));
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(lock_file_shared) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/shared.txt", "x", 1);
|
||||
|
||||
const char *body =
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
"<lockinfo xmlns=\"DAV:\">"
|
||||
"<lockscope><shared/></lockscope>"
|
||||
"<locktype><write/></locktype>"
|
||||
"</lockinfo>";
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "LOCK", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/shared.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Content-Type", "application/xml");
|
||||
ctx->request.body = strdup(body);
|
||||
ctx->request.body_len = strlen(body);
|
||||
ctx->request.content_length = strlen(body);
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_200_OK, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(lock_collection_depth_infinity) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_create_collection(ctx->fixture->storage, "/folder");
|
||||
storage_write_file(ctx->fixture->storage, "/folder/child.txt", "x", 1);
|
||||
|
||||
const char *body =
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
"<lockinfo xmlns=\"DAV:\">"
|
||||
"<lockscope><exclusive/></lockscope>"
|
||||
"<locktype><write/></locktype>"
|
||||
"</lockinfo>";
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "LOCK", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/folder", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Depth", "infinity");
|
||||
http_request_add_header(&ctx->request, "Content-Type", "application/xml");
|
||||
ctx->request.body = strdup(body);
|
||||
ctx->request.body_len = strlen(body);
|
||||
ctx->request.content_length = strlen(body);
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_200_OK, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(lock_not_found) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
const char *body =
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
"<lockinfo xmlns=\"DAV:\">"
|
||||
"<lockscope><exclusive/></lockscope>"
|
||||
"<locktype><write/></locktype>"
|
||||
"</lockinfo>";
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "LOCK", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/nonexistent.txt", sizeof(ctx->request.uri) - 1);
|
||||
ctx->request.body = strdup(body);
|
||||
ctx->request.body_len = strlen(body);
|
||||
ctx->request.content_length = strlen(body);
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_404_NOT_FOUND, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(lock_already_locked_exclusive) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/locked.txt", "x", 1);
|
||||
|
||||
lock_info_t lock;
|
||||
memset(&lock, 0, sizeof(lock));
|
||||
strncpy(lock.owner, "user1", sizeof(lock.owner) - 1);
|
||||
lock.scope = LOCK_SCOPE_EXCLUSIVE;
|
||||
lock.type = LOCK_TYPE_WRITE;
|
||||
lock.timeout = 3600;
|
||||
lock_manager_acquire(ctx->fixture->locks, "/locked.txt", &lock);
|
||||
|
||||
const char *body =
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
"<lockinfo xmlns=\"DAV:\">"
|
||||
"<lockscope><exclusive/></lockscope>"
|
||||
"<locktype><write/></locktype>"
|
||||
"</lockinfo>";
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "LOCK", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/locked.txt", sizeof(ctx->request.uri) - 1);
|
||||
ctx->request.body = strdup(body);
|
||||
ctx->request.body_len = strlen(body);
|
||||
ctx->request.content_length = strlen(body);
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_423_LOCKED, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(lock_refresh) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/refresh.txt", "x", 1);
|
||||
|
||||
lock_info_t lock;
|
||||
memset(&lock, 0, sizeof(lock));
|
||||
strncpy(lock.owner, "user1", sizeof(lock.owner) - 1);
|
||||
lock.scope = LOCK_SCOPE_EXCLUSIVE;
|
||||
lock.type = LOCK_TYPE_WRITE;
|
||||
lock.timeout = 100;
|
||||
lock_manager_acquire(ctx->fixture->locks, "/refresh.txt", &lock);
|
||||
|
||||
char if_header[256];
|
||||
snprintf(if_header, sizeof(if_header), "(<%s>)", lock.token);
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "LOCK", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/refresh.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "If", if_header);
|
||||
http_request_add_header(&ctx->request, "Timeout", "Second-7200");
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_200_OK, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(lock_response_contains_lockdiscovery) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/discover.txt", "x", 1);
|
||||
|
||||
const char *body =
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
"<lockinfo xmlns=\"DAV:\">"
|
||||
"<lockscope><exclusive/></lockscope>"
|
||||
"<locktype><write/></locktype>"
|
||||
"</lockinfo>";
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "LOCK", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/discover.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Content-Type", "application/xml");
|
||||
ctx->request.body = strdup(body);
|
||||
ctx->request.body_len = strlen(body);
|
||||
ctx->request.content_length = strlen(body);
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_200_OK, ctx->response.status);
|
||||
ASSERT_NOT_NULL(ctx->response.body);
|
||||
ASSERT_TRUE(strstr(ctx->response.body, "lockdiscovery") != NULL);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
#include "../../test_framework.h"
|
||||
#include "../http_endpoints.h"
|
||||
|
||||
TEST_SUITE(webdav_mkcol)
|
||||
|
||||
TEST(mkcol_create_collection) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
endpoint_test_execute(ctx, "MKCOL", "/newcollection", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_201_CREATED, ctx->response.status);
|
||||
|
||||
int exists = storage_exists(ctx->fixture->storage, "/newcollection");
|
||||
ASSERT_TRUE(exists);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(mkcol_nested_collection) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_create_collection(ctx->fixture->storage, "/parent");
|
||||
|
||||
endpoint_test_execute(ctx, "MKCOL", "/parent/child", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_201_CREATED, ctx->response.status);
|
||||
|
||||
int exists = storage_exists(ctx->fixture->storage, "/parent/child");
|
||||
ASSERT_TRUE(exists);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(mkcol_parent_missing_fails) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
endpoint_test_execute(ctx, "MKCOL", "/missing/child", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_409_CONFLICT, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(mkcol_already_exists_fails) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_create_collection(ctx->fixture->storage, "/existing");
|
||||
|
||||
endpoint_test_execute(ctx, "MKCOL", "/existing", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_405_METHOD_NOT_ALLOWED, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(mkcol_file_exists_at_path_fails) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/isfile", "content", 7);
|
||||
|
||||
endpoint_test_execute(ctx, "MKCOL", "/isfile", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_405_METHOD_NOT_ALLOWED, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(mkcol_with_body_fails) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
endpoint_test_execute(ctx, "MKCOL", "/withbody", "some body", 9);
|
||||
|
||||
ASSERT_EQUAL(HTTP_415_UNSUPPORTED_MEDIA_TYPE, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(mkcol_root_not_allowed) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
endpoint_test_execute(ctx, "MKCOL", "/", NULL, 0);
|
||||
|
||||
ASSERT_NOT_EQUAL(HTTP_201_CREATED, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(mkcol_deep_nesting) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_create_collection(ctx->fixture->storage, "/a");
|
||||
storage_create_collection(ctx->fixture->storage, "/a/b");
|
||||
storage_create_collection(ctx->fixture->storage, "/a/b/c");
|
||||
|
||||
endpoint_test_execute(ctx, "MKCOL", "/a/b/c/d", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_201_CREATED, ctx->response.status);
|
||||
|
||||
int exists = storage_exists(ctx->fixture->storage, "/a/b/c/d");
|
||||
ASSERT_TRUE(exists);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
#include "../../test_framework.h"
|
||||
#include "../http_endpoints.h"
|
||||
|
||||
TEST_SUITE(webdav_move)
|
||||
|
||||
TEST(move_file) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/original.txt", "content", 7);
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "MOVE", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/original.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Destination", "/moved.txt");
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_201_CREATED, ctx->response.status);
|
||||
|
||||
int exists = storage_exists(ctx->fixture->storage, "/moved.txt");
|
||||
ASSERT_TRUE(exists);
|
||||
|
||||
exists = storage_exists(ctx->fixture->storage, "/original.txt");
|
||||
ASSERT_FALSE(exists);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(move_collection) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_create_collection(ctx->fixture->storage, "/oldfolder");
|
||||
storage_write_file(ctx->fixture->storage, "/oldfolder/file.txt", "data", 4);
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "MOVE", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/oldfolder", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Destination", "/newfolder");
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_201_CREATED, ctx->response.status);
|
||||
|
||||
int exists = storage_exists(ctx->fixture->storage, "/newfolder");
|
||||
ASSERT_TRUE(exists);
|
||||
exists = storage_exists(ctx->fixture->storage, "/newfolder/file.txt");
|
||||
ASSERT_TRUE(exists);
|
||||
exists = storage_exists(ctx->fixture->storage, "/oldfolder");
|
||||
ASSERT_FALSE(exists);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(move_source_not_found) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "MOVE", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/nonexistent.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Destination", "/dest.txt");
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_404_NOT_FOUND, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(move_missing_destination_header) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/source.txt", "data", 4);
|
||||
|
||||
endpoint_test_execute(ctx, "MOVE", "/source.txt", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_400_BAD_REQUEST, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(move_overwrite_true) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/src.txt", "source", 6);
|
||||
storage_write_file(ctx->fixture->storage, "/dst.txt", "destination", 11);
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "MOVE", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/src.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Destination", "/dst.txt");
|
||||
http_request_add_header(&ctx->request, "Overwrite", "T");
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_204_NO_CONTENT, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(move_overwrite_false_fails) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/src.txt", "source", 6);
|
||||
storage_write_file(ctx->fixture->storage, "/dst.txt", "destination", 11);
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "MOVE", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/src.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Destination", "/dst.txt");
|
||||
http_request_add_header(&ctx->request, "Overwrite", "F");
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_412_PRECONDITION_FAILED, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(move_dest_parent_missing) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/src.txt", "data", 4);
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "MOVE", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/src.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Destination", "/missing/dst.txt");
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_409_CONFLICT, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(move_locked_source_fails) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/locked.txt", "data", 4);
|
||||
|
||||
lock_info_t lock;
|
||||
memset(&lock, 0, sizeof(lock));
|
||||
strncpy(lock.owner, "user1", sizeof(lock.owner) - 1);
|
||||
lock.scope = LOCK_SCOPE_EXCLUSIVE;
|
||||
lock.type = LOCK_TYPE_WRITE;
|
||||
lock.timeout = 3600;
|
||||
lock_manager_acquire(ctx->fixture->locks, "/locked.txt", &lock);
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "MOVE", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/locked.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Destination", "/unlocked.txt");
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_423_LOCKED, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(move_rename_in_place) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_create_collection(ctx->fixture->storage, "/folder");
|
||||
storage_write_file(ctx->fixture->storage, "/folder/old.txt", "data", 4);
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "MOVE", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/folder/old.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Destination", "/folder/new.txt");
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_201_CREATED, ctx->response.status);
|
||||
|
||||
int exists = storage_exists(ctx->fixture->storage, "/folder/new.txt");
|
||||
ASSERT_TRUE(exists);
|
||||
exists = storage_exists(ctx->fixture->storage, "/folder/old.txt");
|
||||
ASSERT_FALSE(exists);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
#include "../../test_framework.h"
|
||||
#include "../http_endpoints.h"
|
||||
|
||||
TEST_SUITE(webdav_options)
|
||||
|
||||
TEST(options_returns_200) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
endpoint_test_execute(ctx, "OPTIONS", "/", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_200_OK, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(options_includes_dav_header) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
endpoint_test_execute(ctx, "OPTIONS", "/", NULL, 0);
|
||||
|
||||
ASSERT_TRUE(endpoint_response_has_header(ctx, "DAV", NULL));
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(options_includes_allow_header) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
endpoint_test_execute(ctx, "OPTIONS", "/", NULL, 0);
|
||||
|
||||
const char *allow = endpoint_response_get_header(ctx, "Allow");
|
||||
ASSERT_NOT_NULL(allow);
|
||||
ASSERT_TRUE(strstr(allow, "GET") != NULL);
|
||||
ASSERT_TRUE(strstr(allow, "PUT") != NULL);
|
||||
ASSERT_TRUE(strstr(allow, "DELETE") != NULL);
|
||||
ASSERT_TRUE(strstr(allow, "PROPFIND") != NULL);
|
||||
ASSERT_TRUE(strstr(allow, "MKCOL") != NULL);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(options_star_uri) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
endpoint_test_execute(ctx, "OPTIONS", "*", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_200_OK, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(options_on_collection) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_create_collection(ctx->fixture->storage, "/testcol");
|
||||
|
||||
endpoint_test_execute(ctx, "OPTIONS", "/testcol", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_200_OK, ctx->response.status);
|
||||
ASSERT_TRUE(endpoint_response_has_header(ctx, "DAV", NULL));
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(options_on_file) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/testfile.txt", "data", 4);
|
||||
|
||||
endpoint_test_execute(ctx, "OPTIONS", "/testfile.txt", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_200_OK, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
#include "../../test_framework.h"
|
||||
#include "../http_endpoints.h"
|
||||
|
||||
TEST_SUITE(webdav_propfind)
|
||||
|
||||
TEST(propfind_file_depth_0) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/test.txt", "content", 7);
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "PROPFIND", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/test.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Depth", "0");
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_207_MULTI_STATUS, ctx->response.status);
|
||||
ASSERT_NOT_NULL(ctx->response.body);
|
||||
ASSERT_TRUE(strstr(ctx->response.body, "multistatus") != NULL);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(propfind_collection_depth_0) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_create_collection(ctx->fixture->storage, "/folder");
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "PROPFIND", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/folder", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Depth", "0");
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_207_MULTI_STATUS, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(propfind_collection_depth_1) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_create_collection(ctx->fixture->storage, "/folder");
|
||||
storage_write_file(ctx->fixture->storage, "/folder/file1.txt", "a", 1);
|
||||
storage_write_file(ctx->fixture->storage, "/folder/file2.txt", "b", 1);
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "PROPFIND", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/folder", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Depth", "1");
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_207_MULTI_STATUS, ctx->response.status);
|
||||
ASSERT_TRUE(strstr(ctx->response.body, "file1.txt") != NULL);
|
||||
ASSERT_TRUE(strstr(ctx->response.body, "file2.txt") != NULL);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(propfind_collection_depth_infinity) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_create_collection(ctx->fixture->storage, "/root");
|
||||
storage_create_collection(ctx->fixture->storage, "/root/sub");
|
||||
storage_write_file(ctx->fixture->storage, "/root/sub/deep.txt", "x", 1);
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "PROPFIND", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/root", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Depth", "infinity");
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_207_MULTI_STATUS, ctx->response.status);
|
||||
ASSERT_TRUE(strstr(ctx->response.body, "deep.txt") != NULL);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(propfind_not_found) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "PROPFIND", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/nonexistent", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Depth", "0");
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_404_NOT_FOUND, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(propfind_allprop) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/props.txt", "content", 7);
|
||||
|
||||
const char *body = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
"<propfind xmlns=\"DAV:\"><allprop/></propfind>";
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "PROPFIND", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/props.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Depth", "0");
|
||||
http_request_add_header(&ctx->request, "Content-Type", "application/xml");
|
||||
ctx->request.body = strdup(body);
|
||||
ctx->request.body_len = strlen(body);
|
||||
ctx->request.content_length = strlen(body);
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_207_MULTI_STATUS, ctx->response.status);
|
||||
ASSERT_TRUE(strstr(ctx->response.body, "getcontentlength") != NULL);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(propfind_propname) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/propname.txt", "x", 1);
|
||||
|
||||
const char *body = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
"<propfind xmlns=\"DAV:\"><propname/></propfind>";
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "PROPFIND", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/propname.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Depth", "0");
|
||||
ctx->request.body = strdup(body);
|
||||
ctx->request.body_len = strlen(body);
|
||||
ctx->request.content_length = strlen(body);
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_207_MULTI_STATUS, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(propfind_root) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "PROPFIND", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Depth", "0");
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_207_MULTI_STATUS, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
#include "../../test_framework.h"
|
||||
#include "../http_endpoints.h"
|
||||
|
||||
TEST_SUITE(webdav_proppatch)
|
||||
|
||||
TEST(proppatch_set_property) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/file.txt", "content", 7);
|
||||
|
||||
const char *body =
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
"<propertyupdate xmlns=\"DAV:\">"
|
||||
"<set><prop>"
|
||||
"<displayname>My File</displayname>"
|
||||
"</prop></set>"
|
||||
"</propertyupdate>";
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "PROPPATCH", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/file.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Content-Type", "application/xml");
|
||||
ctx->request.body = strdup(body);
|
||||
ctx->request.body_len = strlen(body);
|
||||
ctx->request.content_length = strlen(body);
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_207_MULTI_STATUS, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(proppatch_remove_property) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/file.txt", "content", 7);
|
||||
|
||||
const char *body =
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
"<propertyupdate xmlns=\"DAV:\">"
|
||||
"<remove><prop>"
|
||||
"<displayname/>"
|
||||
"</prop></remove>"
|
||||
"</propertyupdate>";
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "PROPPATCH", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/file.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Content-Type", "application/xml");
|
||||
ctx->request.body = strdup(body);
|
||||
ctx->request.body_len = strlen(body);
|
||||
ctx->request.content_length = strlen(body);
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_207_MULTI_STATUS, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(proppatch_not_found) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
const char *body =
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
"<propertyupdate xmlns=\"DAV:\">"
|
||||
"<set><prop><displayname>x</displayname></prop></set>"
|
||||
"</propertyupdate>";
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "PROPPATCH", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/nonexistent.txt", sizeof(ctx->request.uri) - 1);
|
||||
ctx->request.body = strdup(body);
|
||||
ctx->request.body_len = strlen(body);
|
||||
ctx->request.content_length = strlen(body);
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_404_NOT_FOUND, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(proppatch_custom_namespace) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/custom.txt", "x", 1);
|
||||
|
||||
const char *body =
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
"<propertyupdate xmlns=\"DAV:\" xmlns:custom=\"http://example.com/ns\">"
|
||||
"<set><prop>"
|
||||
"<custom:myprop>myvalue</custom:myprop>"
|
||||
"</prop></set>"
|
||||
"</propertyupdate>";
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "PROPPATCH", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/custom.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Content-Type", "application/xml");
|
||||
ctx->request.body = strdup(body);
|
||||
ctx->request.body_len = strlen(body);
|
||||
ctx->request.content_length = strlen(body);
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_207_MULTI_STATUS, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(proppatch_on_collection) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_create_collection(ctx->fixture->storage, "/folder");
|
||||
|
||||
const char *body =
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
"<propertyupdate xmlns=\"DAV:\">"
|
||||
"<set><prop><displayname>My Folder</displayname></prop></set>"
|
||||
"</propertyupdate>";
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "PROPPATCH", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/folder", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Content-Type", "application/xml");
|
||||
ctx->request.body = strdup(body);
|
||||
ctx->request.body_len = strlen(body);
|
||||
ctx->request.content_length = strlen(body);
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_207_MULTI_STATUS, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(proppatch_locked_fails) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/locked.txt", "x", 1);
|
||||
|
||||
lock_info_t lock;
|
||||
memset(&lock, 0, sizeof(lock));
|
||||
strncpy(lock.owner, "user1", sizeof(lock.owner) - 1);
|
||||
lock.scope = LOCK_SCOPE_EXCLUSIVE;
|
||||
lock.type = LOCK_TYPE_WRITE;
|
||||
lock.timeout = 3600;
|
||||
lock_manager_acquire(ctx->fixture->locks, "/locked.txt", &lock);
|
||||
|
||||
const char *body =
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
"<propertyupdate xmlns=\"DAV:\">"
|
||||
"<set><prop><displayname>x</displayname></prop></set>"
|
||||
"</propertyupdate>";
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "PROPPATCH", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/locked.txt", sizeof(ctx->request.uri) - 1);
|
||||
ctx->request.body = strdup(body);
|
||||
ctx->request.body_len = strlen(body);
|
||||
ctx->request.content_length = strlen(body);
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_423_LOCKED, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
#include "../../test_framework.h"
|
||||
#include "../http_endpoints.h"
|
||||
|
||||
TEST_SUITE(webdav_put)
|
||||
|
||||
TEST(put_create_new_file) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
const char *content = "New file content";
|
||||
endpoint_test_execute(ctx, "PUT", "/newfile.txt", content, strlen(content));
|
||||
|
||||
ASSERT_EQUAL(HTTP_201_CREATED, ctx->response.status);
|
||||
|
||||
int exists = storage_exists(ctx->fixture->storage, "/newfile.txt");
|
||||
ASSERT_TRUE(exists);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(put_overwrite_existing_file) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/existing.txt", "old", 3);
|
||||
|
||||
const char *new_content = "new content";
|
||||
endpoint_test_execute(ctx, "PUT", "/existing.txt", new_content, strlen(new_content));
|
||||
|
||||
ASSERT_EQUAL(HTTP_204_NO_CONTENT, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(put_parent_missing_fails) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
endpoint_test_execute(ctx, "PUT", "/nonexistent/file.txt", "data", 4);
|
||||
|
||||
ASSERT_EQUAL(HTTP_409_CONFLICT, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(put_into_collection) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_create_collection(ctx->fixture->storage, "/folder");
|
||||
|
||||
const char *content = "file in folder";
|
||||
endpoint_test_execute(ctx, "PUT", "/folder/document.txt", content, strlen(content));
|
||||
|
||||
ASSERT_EQUAL(HTTP_201_CREATED, ctx->response.status);
|
||||
|
||||
int exists = storage_exists(ctx->fixture->storage, "/folder/document.txt");
|
||||
ASSERT_TRUE(exists);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(put_binary_data) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
unsigned char binary[] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
|
||||
endpoint_test_execute(ctx, "PUT", "/image.png", (char *)binary, sizeof(binary));
|
||||
|
||||
ASSERT_EQUAL(HTTP_201_CREATED, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(put_empty_file) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
endpoint_test_execute(ctx, "PUT", "/empty.txt", "", 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_201_CREATED, ctx->response.status);
|
||||
|
||||
int exists = storage_exists(ctx->fixture->storage, "/empty.txt");
|
||||
ASSERT_TRUE(exists);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(put_collection_uri_fails) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_create_collection(ctx->fixture->storage, "/mycol");
|
||||
|
||||
endpoint_test_execute(ctx, "PUT", "/mycol/", "data", 4);
|
||||
|
||||
ASSERT_NOT_EQUAL(HTTP_201_CREATED, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(put_path_traversal_blocked) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
endpoint_test_execute(ctx, "PUT", "/../../../tmp/evil.txt", "malicious", 9);
|
||||
|
||||
ASSERT_NOT_EQUAL(HTTP_201_CREATED, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(put_large_file) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
size_t size = 1024 * 1024;
|
||||
char *large_content = malloc(size);
|
||||
ASSERT_NOT_NULL(large_content);
|
||||
memset(large_content, 'X', size);
|
||||
|
||||
endpoint_test_execute(ctx, "PUT", "/largefile.bin", large_content, size);
|
||||
|
||||
ASSERT_EQUAL(HTTP_201_CREATED, ctx->response.status);
|
||||
|
||||
free(large_content);
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
// retoor <retoor@molodetz.nl>
|
||||
#include "../../test_framework.h"
|
||||
#include "../http_endpoints.h"
|
||||
|
||||
TEST_SUITE(webdav_unlock)
|
||||
|
||||
TEST(unlock_success) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/locked.txt", "content", 7);
|
||||
|
||||
lock_info_t lock;
|
||||
memset(&lock, 0, sizeof(lock));
|
||||
strncpy(lock.owner, "user1", sizeof(lock.owner) - 1);
|
||||
lock.scope = LOCK_SCOPE_EXCLUSIVE;
|
||||
lock.type = LOCK_TYPE_WRITE;
|
||||
lock.timeout = 3600;
|
||||
lock_manager_acquire(ctx->fixture->locks, "/locked.txt", &lock);
|
||||
|
||||
char lock_token_header[256];
|
||||
snprintf(lock_token_header, sizeof(lock_token_header), "<%s>", lock.token);
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "UNLOCK", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/locked.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Lock-Token", lock_token_header);
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_204_NO_CONTENT, ctx->response.status);
|
||||
|
||||
int is_locked = lock_manager_is_locked(ctx->fixture->locks, "/locked.txt");
|
||||
ASSERT_FALSE(is_locked);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(unlock_missing_token_header) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/file.txt", "x", 1);
|
||||
|
||||
lock_info_t lock;
|
||||
memset(&lock, 0, sizeof(lock));
|
||||
strncpy(lock.owner, "user1", sizeof(lock.owner) - 1);
|
||||
lock.scope = LOCK_SCOPE_EXCLUSIVE;
|
||||
lock.type = LOCK_TYPE_WRITE;
|
||||
lock.timeout = 3600;
|
||||
lock_manager_acquire(ctx->fixture->locks, "/file.txt", &lock);
|
||||
|
||||
endpoint_test_execute(ctx, "UNLOCK", "/file.txt", NULL, 0);
|
||||
|
||||
ASSERT_EQUAL(HTTP_400_BAD_REQUEST, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(unlock_wrong_token) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/file.txt", "x", 1);
|
||||
|
||||
lock_info_t lock;
|
||||
memset(&lock, 0, sizeof(lock));
|
||||
strncpy(lock.owner, "user1", sizeof(lock.owner) - 1);
|
||||
lock.scope = LOCK_SCOPE_EXCLUSIVE;
|
||||
lock.type = LOCK_TYPE_WRITE;
|
||||
lock.timeout = 3600;
|
||||
lock_manager_acquire(ctx->fixture->locks, "/file.txt", &lock);
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "UNLOCK", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/file.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Lock-Token", "<wrong-token>");
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_409_CONFLICT, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(unlock_not_locked) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/notlocked.txt", "x", 1);
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "UNLOCK", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/notlocked.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Lock-Token", "<some-token>");
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_409_CONFLICT, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(unlock_not_found) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "UNLOCK", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/nonexistent.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Lock-Token", "<some-token>");
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_404_NOT_FOUND, ctx->response.status);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
TEST(unlock_shared_lock) {
|
||||
endpoint_test_ctx_t *ctx = endpoint_test_create();
|
||||
ASSERT_NOT_NULL(ctx);
|
||||
|
||||
storage_write_file(ctx->fixture->storage, "/shared.txt", "x", 1);
|
||||
|
||||
lock_info_t lock1;
|
||||
memset(&lock1, 0, sizeof(lock1));
|
||||
strncpy(lock1.owner, "user1", sizeof(lock1.owner) - 1);
|
||||
lock1.scope = LOCK_SCOPE_SHARED;
|
||||
lock1.type = LOCK_TYPE_WRITE;
|
||||
lock1.timeout = 3600;
|
||||
lock_manager_acquire(ctx->fixture->locks, "/shared.txt", &lock1);
|
||||
|
||||
lock_info_t lock2;
|
||||
memset(&lock2, 0, sizeof(lock2));
|
||||
strncpy(lock2.owner, "user2", sizeof(lock2.owner) - 1);
|
||||
lock2.scope = LOCK_SCOPE_SHARED;
|
||||
lock2.type = LOCK_TYPE_WRITE;
|
||||
lock2.timeout = 3600;
|
||||
lock_manager_acquire(ctx->fixture->locks, "/shared.txt", &lock2);
|
||||
|
||||
char lock_token_header[256];
|
||||
snprintf(lock_token_header, sizeof(lock_token_header), "<%s>", lock1.token);
|
||||
|
||||
http_request_init(&ctx->request);
|
||||
strncpy(ctx->request.method, "UNLOCK", sizeof(ctx->request.method) - 1);
|
||||
strncpy(ctx->request.uri, "/shared.txt", sizeof(ctx->request.uri) - 1);
|
||||
http_request_add_header(&ctx->request, "Lock-Token", lock_token_header);
|
||||
|
||||
http_response_init(&ctx->response);
|
||||
webdav_handle_request(ctx->fixture->storage, ctx->fixture->locks,
|
||||
ctx->fixture->props, &ctx->request, &ctx->response);
|
||||
|
||||
ASSERT_EQUAL(HTTP_204_NO_CONTENT, ctx->response.status);
|
||||
|
||||
int is_locked = lock_manager_is_locked(ctx->fixture->locks, "/shared.txt");
|
||||
ASSERT_TRUE(is_locked);
|
||||
|
||||
endpoint_test_destroy(ctx);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user