various fixes for Spring 2021
- support for 206 return code - fixes to sendfile - add URL variable to testloginapi.sh
This commit is contained in:
parent
07658f3b90
commit
7ba2670512
@ -108,6 +108,9 @@ read_more(struct bufio *self)
|
||||
/* Given an offset into the buffer, return a char *.
|
||||
* This pointer will be valid only until the next call
|
||||
* to any of the bufio_read* function.
|
||||
*
|
||||
* The returned pointer is not guaranteed to point to a
|
||||
* zero-terminated string.
|
||||
*/
|
||||
char *
|
||||
bufio_offset2ptr(struct bufio *self, size_t offset)
|
||||
@ -194,7 +197,7 @@ bufio_read(struct bufio *self, size_t count, size_t *buf_offset)
|
||||
* See sendfile(2) for return value.
|
||||
*/
|
||||
ssize_t
|
||||
bufio_sendfile(struct bufio *self, int fd, off_t *off, int filesize)
|
||||
bufio_sendfile(struct bufio *self, int fd, off_t *off, size_t filesize)
|
||||
{
|
||||
return sendfile(self->socket, fd, off, filesize);
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ ssize_t bufio_readline(struct bufio *self, size_t *line_offset);
|
||||
ssize_t bufio_read(struct bufio *self, size_t count, size_t *buf_offset);
|
||||
char * bufio_offset2ptr(struct bufio *self, size_t offset);
|
||||
size_t bufio_ptr2offset(struct bufio *self, char *ptr);
|
||||
ssize_t bufio_sendfile(struct bufio *self, int fd, off_t *off, int filesize);
|
||||
ssize_t bufio_sendfile(struct bufio *self, int fd, off_t *off, size_t filesize);
|
||||
ssize_t bufio_sendbuffer(struct bufio *self, buffer_t *response);
|
||||
|
||||
#endif /* _BUFIO_H */
|
||||
|
22
src/http.c
22
src/http.c
@ -28,6 +28,7 @@
|
||||
|
||||
// Need macros here because of the sizeof
|
||||
#define CRLF "\r\n"
|
||||
#define CR "\r"
|
||||
#define STARTS_WITH(field_name, header) \
|
||||
(!strncasecmp(field_name, header, sizeof(header) - 1))
|
||||
|
||||
@ -41,6 +42,7 @@ http_parse_request(struct http_transaction *ta)
|
||||
return false;
|
||||
|
||||
char *request = bufio_offset2ptr(ta->client->bufio, req_offset);
|
||||
request[len-2] = '\0'; // replace LF with 0 to ensure zero-termination
|
||||
char *endptr;
|
||||
char *method = strtok_r(request, " ", &endptr);
|
||||
if (method == NULL)
|
||||
@ -59,10 +61,11 @@ http_parse_request(struct http_transaction *ta)
|
||||
|
||||
ta->req_path = bufio_ptr2offset(ta->client->bufio, req_path);
|
||||
|
||||
char *http_version = strtok_r(NULL, CRLF, &endptr);
|
||||
char *http_version = strtok_r(NULL, CR, &endptr);
|
||||
if (http_version == NULL) // would be HTTP 0.9
|
||||
return false;
|
||||
|
||||
// record client's HTTP version in request
|
||||
if (!strcmp(http_version, "HTTP/1.1"))
|
||||
ta->req_version = HTTP_1_1;
|
||||
else if (!strcmp(http_version, "HTTP/1.0"))
|
||||
@ -97,7 +100,7 @@ http_process_headers(struct http_transaction *ta)
|
||||
char *field_name = strtok_r(header, ":", &endptr);
|
||||
char *field_value = strtok_r(NULL, " \t", &endptr); // skip leading & trailing OWS
|
||||
|
||||
if (field_name == NULL)
|
||||
if (field_name == NULL || field_value == NULL)
|
||||
return false;
|
||||
|
||||
// printf("Header: %s: %s\n", field_name, field_value);
|
||||
@ -147,6 +150,9 @@ start_response(struct http_transaction * ta, buffer_t *res)
|
||||
case HTTP_OK:
|
||||
buffer_appends(res, "200 OK");
|
||||
break;
|
||||
case HTTP_PARTIAL_CONTENT:
|
||||
buffer_appends(res, "206 Partial Content");
|
||||
break;
|
||||
case HTTP_BAD_REQUEST:
|
||||
buffer_appends(res, "400 Bad Request");
|
||||
break;
|
||||
@ -295,20 +301,26 @@ handle_static_asset(struct http_transaction *ta, char *basedir)
|
||||
}
|
||||
|
||||
ta->resp_status = HTTP_OK;
|
||||
add_content_length(&ta->resp_headers, st.st_size);
|
||||
http_add_header(&ta->resp_headers, "Content-Type", "%s", guess_mime_type(fname));
|
||||
off_t from = 0, to = st.st_size - 1;
|
||||
|
||||
off_t content_length = to + 1 - from;
|
||||
add_content_length(&ta->resp_headers, content_length);
|
||||
|
||||
bool success = send_response_header(ta);
|
||||
if (!success)
|
||||
goto out;
|
||||
|
||||
success = bufio_sendfile(ta->client->bufio, filefd, NULL, st.st_size) == st.st_size;
|
||||
// sendfile may send fewer bytes than requested, hence the loop
|
||||
while (success && from <= to)
|
||||
success = bufio_sendfile(ta->client->bufio, filefd, &from, to + 1 - from) > 0;
|
||||
|
||||
out:
|
||||
close(filefd);
|
||||
return success;
|
||||
}
|
||||
|
||||
static int
|
||||
static bool
|
||||
handle_api(struct http_transaction *ta)
|
||||
{
|
||||
return send_error(ta, HTTP_NOT_FOUND, "API not implemented");
|
||||
|
@ -20,6 +20,7 @@ enum http_version {
|
||||
|
||||
enum http_response_status {
|
||||
HTTP_OK = 200,
|
||||
HTTP_PARTIAL_CONTENT = 206,
|
||||
HTTP_BAD_REQUEST = 400,
|
||||
HTTP_PERMISSION_DENIED = 403,
|
||||
HTTP_NOT_FOUND = 404,
|
||||
|
@ -2,8 +2,13 @@
|
||||
# change this as per instruction to avoid conflicts.
|
||||
PORT=10000
|
||||
|
||||
# to test against a working implementation (and see the intended responses)
|
||||
# change this URL=http://theta.cs.vt.edu:3000/
|
||||
URL=http://localhost:${PORT}
|
||||
|
||||
COOKIEJAR=cookies.txt
|
||||
|
||||
|
||||
# clear cookies
|
||||
/bin/rm ${COOKIEJAR}
|
||||
|
||||
@ -12,20 +17,20 @@ curl -v -H "Content-Type: application/json" \
|
||||
-c ${COOKIEJAR} \
|
||||
-X POST \
|
||||
-d '{"username":"user0","password":"thepassword"}' \
|
||||
http://localhost:${PORT}/api/login
|
||||
${URL}/api/login
|
||||
|
||||
# this should succeed if the password is correct
|
||||
curl -v \
|
||||
-b ${COOKIEJAR} \
|
||||
http://localhost:${PORT}/api/login
|
||||
${URL}/api/login
|
||||
|
||||
# create a 'private' folder first.
|
||||
# this should fail since credentials were not presented
|
||||
curl -v \
|
||||
http://localhost:${PORT}/private/secret.txt
|
||||
${URL}/private/secret.txt
|
||||
|
||||
# this should succeed since credentials were presented
|
||||
curl -v \
|
||||
-b ${COOKIEJAR} \
|
||||
http://localhost:${PORT}/private/secret.txt
|
||||
${URl}/private/secret.txt
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user