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 *.
|
/* Given an offset into the buffer, return a char *.
|
||||||
* This pointer will be valid only until the next call
|
* This pointer will be valid only until the next call
|
||||||
* to any of the bufio_read* function.
|
* to any of the bufio_read* function.
|
||||||
|
*
|
||||||
|
* The returned pointer is not guaranteed to point to a
|
||||||
|
* zero-terminated string.
|
||||||
*/
|
*/
|
||||||
char *
|
char *
|
||||||
bufio_offset2ptr(struct bufio *self, size_t offset)
|
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.
|
* See sendfile(2) for return value.
|
||||||
*/
|
*/
|
||||||
ssize_t
|
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);
|
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);
|
ssize_t bufio_read(struct bufio *self, size_t count, size_t *buf_offset);
|
||||||
char * bufio_offset2ptr(struct bufio *self, size_t offset);
|
char * bufio_offset2ptr(struct bufio *self, size_t offset);
|
||||||
size_t bufio_ptr2offset(struct bufio *self, char *ptr);
|
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);
|
ssize_t bufio_sendbuffer(struct bufio *self, buffer_t *response);
|
||||||
|
|
||||||
#endif /* _BUFIO_H */
|
#endif /* _BUFIO_H */
|
||||||
|
22
src/http.c
22
src/http.c
@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
// Need macros here because of the sizeof
|
// Need macros here because of the sizeof
|
||||||
#define CRLF "\r\n"
|
#define CRLF "\r\n"
|
||||||
|
#define CR "\r"
|
||||||
#define STARTS_WITH(field_name, header) \
|
#define STARTS_WITH(field_name, header) \
|
||||||
(!strncasecmp(field_name, header, sizeof(header) - 1))
|
(!strncasecmp(field_name, header, sizeof(header) - 1))
|
||||||
|
|
||||||
@ -41,6 +42,7 @@ http_parse_request(struct http_transaction *ta)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
char *request = bufio_offset2ptr(ta->client->bufio, req_offset);
|
char *request = bufio_offset2ptr(ta->client->bufio, req_offset);
|
||||||
|
request[len-2] = '\0'; // replace LF with 0 to ensure zero-termination
|
||||||
char *endptr;
|
char *endptr;
|
||||||
char *method = strtok_r(request, " ", &endptr);
|
char *method = strtok_r(request, " ", &endptr);
|
||||||
if (method == NULL)
|
if (method == NULL)
|
||||||
@ -59,10 +61,11 @@ http_parse_request(struct http_transaction *ta)
|
|||||||
|
|
||||||
ta->req_path = bufio_ptr2offset(ta->client->bufio, req_path);
|
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
|
if (http_version == NULL) // would be HTTP 0.9
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// record client's HTTP version in request
|
||||||
if (!strcmp(http_version, "HTTP/1.1"))
|
if (!strcmp(http_version, "HTTP/1.1"))
|
||||||
ta->req_version = HTTP_1_1;
|
ta->req_version = HTTP_1_1;
|
||||||
else if (!strcmp(http_version, "HTTP/1.0"))
|
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_name = strtok_r(header, ":", &endptr);
|
||||||
char *field_value = strtok_r(NULL, " \t", &endptr); // skip leading & trailing OWS
|
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;
|
return false;
|
||||||
|
|
||||||
// printf("Header: %s: %s\n", field_name, field_value);
|
// 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:
|
case HTTP_OK:
|
||||||
buffer_appends(res, "200 OK");
|
buffer_appends(res, "200 OK");
|
||||||
break;
|
break;
|
||||||
|
case HTTP_PARTIAL_CONTENT:
|
||||||
|
buffer_appends(res, "206 Partial Content");
|
||||||
|
break;
|
||||||
case HTTP_BAD_REQUEST:
|
case HTTP_BAD_REQUEST:
|
||||||
buffer_appends(res, "400 Bad Request");
|
buffer_appends(res, "400 Bad Request");
|
||||||
break;
|
break;
|
||||||
@ -295,20 +301,26 @@ handle_static_asset(struct http_transaction *ta, char *basedir)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ta->resp_status = HTTP_OK;
|
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));
|
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);
|
bool success = send_response_header(ta);
|
||||||
if (!success)
|
if (!success)
|
||||||
goto out;
|
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:
|
out:
|
||||||
close(filefd);
|
close(filefd);
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static bool
|
||||||
handle_api(struct http_transaction *ta)
|
handle_api(struct http_transaction *ta)
|
||||||
{
|
{
|
||||||
return send_error(ta, HTTP_NOT_FOUND, "API not implemented");
|
return send_error(ta, HTTP_NOT_FOUND, "API not implemented");
|
||||||
|
@ -20,6 +20,7 @@ enum http_version {
|
|||||||
|
|
||||||
enum http_response_status {
|
enum http_response_status {
|
||||||
HTTP_OK = 200,
|
HTTP_OK = 200,
|
||||||
|
HTTP_PARTIAL_CONTENT = 206,
|
||||||
HTTP_BAD_REQUEST = 400,
|
HTTP_BAD_REQUEST = 400,
|
||||||
HTTP_PERMISSION_DENIED = 403,
|
HTTP_PERMISSION_DENIED = 403,
|
||||||
HTTP_NOT_FOUND = 404,
|
HTTP_NOT_FOUND = 404,
|
||||||
|
@ -2,8 +2,13 @@
|
|||||||
# change this as per instruction to avoid conflicts.
|
# change this as per instruction to avoid conflicts.
|
||||||
PORT=10000
|
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
|
COOKIEJAR=cookies.txt
|
||||||
|
|
||||||
|
|
||||||
# clear cookies
|
# clear cookies
|
||||||
/bin/rm ${COOKIEJAR}
|
/bin/rm ${COOKIEJAR}
|
||||||
|
|
||||||
@ -12,20 +17,20 @@ curl -v -H "Content-Type: application/json" \
|
|||||||
-c ${COOKIEJAR} \
|
-c ${COOKIEJAR} \
|
||||||
-X POST \
|
-X POST \
|
||||||
-d '{"username":"user0","password":"thepassword"}' \
|
-d '{"username":"user0","password":"thepassword"}' \
|
||||||
http://localhost:${PORT}/api/login
|
${URL}/api/login
|
||||||
|
|
||||||
# this should succeed if the password is correct
|
# this should succeed if the password is correct
|
||||||
curl -v \
|
curl -v \
|
||||||
-b ${COOKIEJAR} \
|
-b ${COOKIEJAR} \
|
||||||
http://localhost:${PORT}/api/login
|
${URL}/api/login
|
||||||
|
|
||||||
# create a 'private' folder first.
|
# create a 'private' folder first.
|
||||||
# this should fail since credentials were not presented
|
# this should fail since credentials were not presented
|
||||||
curl -v \
|
curl -v \
|
||||||
http://localhost:${PORT}/private/secret.txt
|
${URL}/private/secret.txt
|
||||||
|
|
||||||
# this should succeed since credentials were presented
|
# this should succeed since credentials were presented
|
||||||
curl -v \
|
curl -v \
|
||||||
-b ${COOKIEJAR} \
|
-b ${COOKIEJAR} \
|
||||||
http://localhost:${PORT}/private/secret.txt
|
${URl}/private/secret.txt
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user