static int listener0(void *ctx, HTTPServerRef const server, HTTPConnectionRef const conn) { HTTPMethod method; str_t URI[URI_MAX]; ssize_t len = HTTPConnectionReadRequest(conn, &method, URI, sizeof(URI)); if(UV_EOF == len) { // HACK: Force the connection to realize it's dead. // Otherwise there is a timeout period of like 15-20 seconds // and we can run out of file descriptors. I suspect this // is a bug with libuv, but I'm not sure. HTTPConnectionWrite(conn, (byte_t const *)STR_LEN("x")); HTTPConnectionFlush(conn); return 0; } if(UV_EMSGSIZE == len) return 414; // Request-URI Too Large if(len < 0) { fprintf(stderr, "Request error: %s\n", uv_strerror(len)); return 500; } HTTPHeadersRef headers; int rc = HTTPHeadersCreateFromConnection(conn, &headers); if(UV_EMSGSIZE == rc) return 431; // Request Header Fields Too Large if(rc < 0) return 500; strarg_t const host = HTTPHeadersGet(headers, "host"); str_t domain[1023+1]; domain[0] = '\0'; if(host) sscanf(host, "%1023[^:]", domain); // TODO: Verify Host header to prevent DNS rebinding. if(SERVER_PORT_TLS && server == server_raw) { // Redirect from HTTP to HTTPS if('\0' == domain[0]) return 400; strarg_t const port = SERVER_PORT_TLS; str_t loc[URI_MAX]; rc = snprintf(loc, sizeof(loc), "https://%s:%s%s", domain, port, URI); if(rc >= sizeof(loc)) 414; // Request-URI Too Large if(rc < 0) return 500; HTTPConnectionSendRedirect(conn, 301, loc); return 0; } strarg_t const cookie = HTTPHeadersGet(headers, "cookie"); SLNSessionCacheRef const cache = SLNRepoGetSessionCache(repo); SLNSessionRef session = NULL; rc = SLNSessionCacheCopyActiveSession(cache, cookie, &session); if(rc < 0) return 500; // Note: null session is valid (zero permissions). rc = -1; rc = rc >= 0 ? rc : SLNServerDispatch(repo, session, conn, method, URI, headers); rc = rc >= 0 ? rc : BlogDispatch(blog, session, conn, method, URI, headers); SLNSessionRelease(&session); HTTPHeadersFree(&headers); return rc; }
static int POST_auth(BlogRef const blog, SLNSessionRef const session, HTTPConnectionRef const conn, HTTPMethod const method, strarg_t const URI, HTTPHeadersRef const headers) { if(HTTP_POST != method) return -1; if(0 != uripathcmp("/auth", URI, NULL)) return -1; // TODO: Check that Content-Type is application/x-www-form-urlencoded. str_t formdata[AUTH_FORM_MAX]; ssize_t len = HTTPConnectionReadBodyStatic(conn, (byte_t *)formdata, sizeof(formdata)-1); if(UV_EMSGSIZE == len) return 413; // Request Entity Too Large if(len < 0) return 500; formdata[len] = '\0'; SLNSessionCacheRef const cache = SLNRepoGetSessionCache(blog->repo); static strarg_t const fields[] = { "action-login", "action-register", "user", "pass", "token", // TODO: CSRF protection }; str_t *values[numberof(fields)] = {}; QSValuesParse(formdata, values, fields, numberof(fields)); if(values[1]) { QSValuesCleanup(values, numberof(values)); return 501; // TODO: Not Implemented } if(!values[0]) { QSValuesCleanup(values, numberof(values)); return 400; // Not login? } SLNSessionRef s; int rc = SLNSessionCacheCreateSession(cache, values[2], values[3], &s); // TODO QSValuesCleanup(values, numberof(values)); if(rc < 0) { HTTPConnectionSendRedirect(conn, 303, "/account?err=1"); return 0; } str_t *cookie = SLNSessionCopyCookie(s); SLNSessionRelease(&s); if(!cookie) return 500; HTTPConnectionWriteResponse(conn, 303, "See Other"); HTTPConnectionWriteHeader(conn, "Location", "/"); HTTPConnectionWriteSetCookie(conn, cookie, "/", 60 * 60 * 24 * 365); HTTPConnectionWriteContentLength(conn, 0); HTTPConnectionBeginBody(conn); HTTPConnectionEnd(conn); FREE(&cookie); return 0; }
static int listener0(void *ctx, HTTPServerRef const server, HTTPConnectionRef const conn) { HTTPMethod method; str_t URI[URI_MAX]; ssize_t len = HTTPConnectionReadRequest(conn, &method, URI, sizeof(URI)); if(UV_EOF == len) return 0; if(UV_ECONNRESET == len) return 0; if(UV_EMSGSIZE == len) return 414; // Request-URI Too Large if(len < 0) { alogf("Request error: %s\n", uv_strerror(len)); return 500; } HTTPHeadersRef headers; int rc = HTTPHeadersCreateFromConnection(conn, &headers); if(UV_EMSGSIZE == rc) return 431; // Request Header Fields Too Large if(rc < 0) return 500; strarg_t const host = HTTPHeadersGet(headers, "host"); str_t domain[1023+1]; domain[0] = '\0'; if(host) sscanf(host, "%1023[^:]", domain); // TODO: Verify Host header to prevent DNS rebinding. if(SERVER_PORT_TLS && server == server_raw) { // Redirect from HTTP to HTTPS if('\0' == domain[0]) return 400; strarg_t const port = SERVER_PORT_TLS; str_t loc[URI_MAX]; rc = snprintf(loc, sizeof(loc), "https://%s:%s%s", domain, port, URI); if(rc >= sizeof(loc)) 414; // Request-URI Too Large if(rc < 0) return 500; HTTPConnectionSendRedirect(conn, 301, loc); return 0; } strarg_t const cookie = HTTPHeadersGet(headers, "cookie"); SLNSessionCacheRef const cache = SLNRepoGetSessionCache(repo); SLNSessionRef session = NULL; rc = SLNSessionCacheCopyActiveSession(cache, cookie, &session); if(rc < 0) return 500; // Note: null session is valid (zero permissions). rc = -1; rc = rc >= 0 ? rc : SLNServerDispatch(repo, session, conn, method, URI, headers); rc = rc >= 0 ? rc : BlogDispatch(blog, session, conn, method, URI, headers); SLNSessionRelease(&session); HTTPHeadersFree(&headers); return rc; }
SLNPullRef SLNRepoCreatePull(SLNRepoRef const repo, uint64_t const pullID, uint64_t const userID, strarg_t const host, strarg_t const sessionid, strarg_t const query) { SLNPullRef pull = calloc(1, sizeof(struct SLNPull)); if(!pull) return NULL; SLNSessionCacheRef const cache = SLNRepoGetSessionCache(repo); pull->pullID = pullID; pull->session = SLNSessionCreateInternal(cache, 0, NULL, NULL, userID, SLN_RDWR, NULL); // TODO: How to create this properly? pull->host = strdup(host); pull->cookie = aasprintf("s=%s", sessionid ? sessionid : ""); // pull->query = strdup(query); assert(!query || '\0' == query[0]); // TODO if(!pull->session || !pull->host || !pull->cookie) { SLNPullFree(&pull); return NULL; } async_mutex_init(pull->connlock, 0); async_mutex_init(pull->mutex, 0); async_cond_init(pull->cond, 0); pull->stop = true; return pull; }