static int accept_sub(SLNSessionRef const session, strarg_t const knownURI, HTTPConnectionRef const conn, HTTPHeadersRef const headers) { strarg_t const type = HTTPHeadersGet(headers, "Content-Type"); if(!type) return 415; // Unsupported Media Type SLNSubmissionRef sub = NULL; int rc = SLNSubmissionCreate(session, knownURI, type, &sub); if(rc < 0) goto cleanup; for(;;) { uv_buf_t buf[1] = {}; rc = HTTPConnectionReadBody(conn, buf); if(rc < 0) goto cleanup; if(0 == buf->len) break; rc = SLNSubmissionWrite(sub, (byte_t const *)buf->base, buf->len); if(rc < 0) goto cleanup; } rc = SLNSubmissionEnd(sub); if(rc < 0) goto cleanup; rc = SLNSubmissionStoreBatch(&sub, 1); if(rc < 0) goto cleanup; strarg_t const location = SLNSubmissionGetPrimaryURI(sub); if(!location) rc = UV_ENOMEM; if(rc < 0) goto cleanup; created(location, conn); cleanup: SLNSubmissionFree(&sub); if(UV_EACCES == rc) return 403; // Forbidden if(UV_UNKNOWN == rc) return 400; // Bad Request if(SLN_HASHMISMATCH == rc) return 409; // Conflict if(rc < 0) return 500; return 0; }
ssize_t HTTPConnectionReadBodyStatic(HTTPConnectionRef const conn, byte_t *const out, size_t const max) { if(!conn) return UV_EINVAL; ssize_t len = 0; for(;;) { uv_buf_t buf[1]; int rc = HTTPConnectionReadBody(conn, buf); if(rc < 0) return rc; if(!buf->len) break; if(len+buf->len >= max) return UV_EMSGSIZE; memcpy(out, buf->base, buf->len); len += buf->len; } return len; }
static int import(SLNPullRef const pull, strarg_t const URI, size_t const pos, HTTPConnectionRef *const conn) { if(!pull) return 0; // TODO: Even if there's nothing to do, we have to enqueue something to fill up our reserved slots. I guess it's better than doing a lot of work inside the connection lock, but there's got to be a better way. SLNSubmissionRef sub = NULL; HTTPHeadersRef headers = NULL; if(!URI) goto enqueue; str_t algo[SLN_ALGO_SIZE]; str_t hash[SLN_HASH_SIZE]; if(SLNParseURI(URI, algo, hash) < 0) goto enqueue; int rc = SLNSessionGetFileInfo(pull->session, URI, NULL); if(rc >= 0) goto enqueue; db_assertf(DB_NOTFOUND == rc, "Database error: %s", sln_strerror(rc)); // TODO: We're logging out of order when we do it like this... // alogf("Pulling %s\n", URI); if(!*conn) { rc = HTTPConnectionCreateOutgoing(pull->host, 0, conn); if(rc < 0) { alogf("Pull import connection error: %s\n", sln_strerror(rc)); goto fail; } } str_t *path = aasprintf("/sln/file/%s/%s", algo, hash); if(!path) { alogf("Pull aasprintf error\n"); goto fail; } rc = HTTPConnectionWriteRequest(*conn, HTTP_GET, path, pull->host); assert(rc >= 0); // TODO FREE(&path); HTTPConnectionWriteHeader(*conn, "Cookie", pull->cookie); HTTPConnectionBeginBody(*conn); rc = HTTPConnectionEnd(*conn); if(rc < 0) { alogf("Pull import request error: %s\n", sln_strerror(rc)); goto fail; } int const status = HTTPConnectionReadResponseStatus(*conn); if(status < 0) { alogf("Pull import response error: %s\n", sln_strerror(status)); goto fail; } if(status < 200 || status >= 300) { alogf("Pull import status error: %d\n", status); goto fail; } rc = HTTPHeadersCreateFromConnection(*conn, &headers); assert(rc >= 0); // TODO /* if(rc < 0) { alogf("Pull import headers error %s\n", sln_strerror(rc)); goto fail; }*/ strarg_t const type = HTTPHeadersGet(headers, "content-type"); rc = SLNSubmissionCreate(pull->session, URI, &sub); if(rc < 0) { alogf("Pull submission error: %s\n", sln_strerror(rc)); goto fail; } rc = SLNSubmissionSetType(sub, type); if(rc < 0) { alogf("Pull submission type error: %s\n", sln_strerror(rc)); goto fail; } for(;;) { if(pull->stop) goto fail; uv_buf_t buf[1] = {}; rc = HTTPConnectionReadBody(*conn, buf); if(rc < 0) { alogf("Pull download error: %s\n", sln_strerror(rc)); goto fail; } if(0 == buf->len) break; rc = SLNSubmissionWrite(sub, (byte_t *)buf->base, buf->len); if(rc < 0) { alogf("Pull write error\n"); goto fail; } } rc = SLNSubmissionEnd(sub); if(rc < 0) { alogf("Pull submission error: %s\n", sln_strerror(rc)); goto fail; } enqueue: HTTPHeadersFree(&headers); async_mutex_lock(pull->mutex); pull->queue[pos] = sub; sub = NULL; pull->filled[pos] = true; async_cond_broadcast(pull->cond); async_mutex_unlock(pull->mutex); return 0; fail: HTTPHeadersFree(&headers); SLNSubmissionFree(&sub); HTTPConnectionFree(conn); return -1; }