diff --git a/README.md b/README.md index c14437e..9f4d269 100644 --- a/README.md +++ b/README.md @@ -123,3 +123,19 @@ Options: ``` Log file of test run is written in js_tests_log.txt in the server/tests/js_tests/tests folder. + +This reference does not provide code for sleeping an app, so +tests that involve sleeping an app will fail. + +There is also a test suite for lightly testing how the implementation handles edge cases. +this can be run with: +``` +server/tests/js_tests/tests$ node testEdgeCases.js + +Usage: node testEdgeCases.js[options] + +Options: + --host IP address of host on which DIAL server under test is running + [string] [required] + --help, -h Show help [boolean] +``` diff --git a/server/dial_data.c b/server/dial_data.c index ac62527..45c4dcd 100644 --- a/server/dial_data.c +++ b/server/dial_data.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Netflix, Inc. + * Copyright (c) 2014-2019 Netflix, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -40,6 +40,13 @@ void set_dial_data_dir(const char *data_dir) { /** * Returns the path where data is stored for the given app. + * + * The DIAL data directory must have been already set. + * + * @param app_name application name. + * @return the location of the application path within the DIAL data + * directory or NULL if memory could not be allocated. + * @see set_dial_data_dir(const char*) */ static char* getAppPath(char *app_name) { size_t name_size = strlen(app_name) + sizeof(dial_data_dir) + 1; diff --git a/server/dial_data.h b/server/dial_data.h index 55a5c7d..a075953 100644 --- a/server/dial_data.h +++ b/server/dial_data.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Netflix, Inc. + * Copyright (c) 2014-2019 Netflix, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -46,6 +46,13 @@ */ #define DIAL_DATA_URI "/dial_data" +/** + * The DIAL data key and value values cannot contain any spaces. They are + * expected to be URL-escaped strings, so any spaces would be represented as + * the '+' character. They have a max length of 255 characters. + * + * THE STRINGS key AND value POINT TO MUST BE DYNAMICALLY ALLOCATED + */ struct DIALData_ { struct DIALData_ *next; char *key; @@ -54,12 +61,45 @@ struct DIALData_ { typedef struct DIALData_ DIALData; +#define DIAL_KEY_OR_VALUE_MAX_LEN (255) +#define DIAL_KEY_OR_VALUE_MAX_LEN_STR "255" + +/** + * Store the DIAL data key/value pairs in the application data store. + * + * Will exit immediately if the data output file cannot be accessed due to + * out-of-memory or I/O errors. + * + * Keys and values are truncated to DIAL_KEY_OR_VALUE_MAX_LEN. + * + * @param app_name application name. + * @param data pointer to head of DIAL data linked list. + */ void store_dial_data(char *app_name, DIALData *data); +/** + * Retrieve the DIAL data key/value pairs from the application data store. + * + * @param app_name application name. + * @return data pointer to head of DIAL data linked list or NULL if + * there is no valid data or if the data output file cannot be accessed + * due to out-of-memory or I/O errors. + */ DIALData *retrieve_dial_data(char *app_name); +/** + * Set the DIAL data directory. + * + * @param data_dir the DIAL data directory path, which must include the + * trailing directory separator (e.g. '/' character). + */ void set_dial_data_dir(const char *data_dir); +/** + * Frees the DIAL data linked list memory. + * + * @param dialData pointer to the DIAL data linked list. + */ void free_dial_data(DIALData **dialData); #endif /* SRC_SERVER_DIAL_DATA_H_ */ diff --git a/server/dial_server.c b/server/dial_server.c index 16d62e6..48c0ddf 100644 --- a/server/dial_server.c +++ b/server/dial_server.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Netflix, Inc. + * Copyright (c) 2014-2019 Netflix, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -94,8 +94,14 @@ static int ds_unlock(DIALServer *ds) { return 1; } -// finds an app and returns a pointer to the previous element's next pointer -// if not found, return a pointer to the last element's next pointer +/** + * Finds an application in the DIAL server application linked list. + * + * @param ds the DIAL server. + * @param app_name application name. + * @return a pointer to the DIAL application; the pointer value may be NULL if + * the application was not found. + */ static DIALApp **find_app(DIALServer *ds, const char *app_name) { DIALApp *app; DIALApp **ret = &ds->apps; @@ -129,9 +135,13 @@ static int url_decode_xml_encode(char *dst, char *src, size_t src_size) { return 1; } -/* - * A bad payload is defined to be an unprintable character or a - * non-ascii character. +/** + * Checks if a payload string contains invalid characters. + * + * @param pPayload payload string. + * @param numBytes length of payload string in bytes (excluding trailing NULL). + * + * @return 1 if the payload contains an unprintable or non-ASCII character. */ static int isBadPayload(const char* pPayload, int numBytes) { int i = 0; diff --git a/server/dial_server.h b/server/dial_server.h index c9b0c7a..5913a08 100644 --- a/server/dial_server.h +++ b/server/dial_server.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Netflix, Inc. + * Copyright (c) 2014-2019 Netflix, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -59,7 +59,9 @@ typedef enum { #define DIAL_MAX_PAYLOAD (4096) /* - * The maximum additionalDataUrl length + * The maximum additionalDataUrl length. + * + * There is no value defined in the DIAL specification. */ #define DIAL_MAX_ADDITIONALURL (1024) @@ -120,6 +122,8 @@ DIALServer *DIAL_create(); * Starts the DIAL server. * * @param[in] ds DIAL server handle + * @return true if the DIAL server was started and the DIAL server handle + * now contains a valid Mongoose context. */ int DIAL_start(DIALServer *ds); @@ -141,7 +145,7 @@ void DIAL_stop(DIALServer *ds); * @param[in] if non-0, the app supports DIALadditionalDataURL. * @param[in] if non-NULL, specifies the CORS allowed origin for this app. * - * @return 1 if successful, 0 otherwise + * @return 1 if successful, 0 if already registered, -1 on error. */ int DIAL_register_app(DIALServer *ds, const char *app_name, struct DIALAppCallbacks *callbacks, @@ -154,7 +158,7 @@ int DIAL_register_app(DIALServer *ds, const char *app_name, * @param[in] ds DIAL server handle * @param[in] app_name Name of the DIAL application * - * @return 1 if successful, 0 otherwise + * @return 1 if successful, 0 if not found, -1 on error. */ int DIAL_unregister_app(DIALServer *ds, const char *app_name); diff --git a/server/mongoose.c b/server/mongoose.c index 97f3af3..0edacc5 100644 --- a/server/mongoose.c +++ b/server/mongoose.c @@ -304,6 +304,14 @@ void mg_send_http_error(struct mg_connection *conn, int status, conn->num_bytes_sent += mg_printf(conn, "%s", buf); } +/** + * Create a new thread. + * + * @param ctx Mongoose context. + * @param func thread function. + * @param param thread function arguments. + * @return the return value of pthread_create. + */ static int start_thread(struct mg_context *ctx, mg_thread_func_t func, void *param) { pthread_t thread_id; diff --git a/server/nf_callbacks.c b/server/nf_callbacks.c index ae414c9..01c9a11 100644 --- a/server/nf_callbacks.c +++ b/server/nf_callbacks.c @@ -1,3 +1,27 @@ +/* + * Copyright (c) 2014-2019 Netflix, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETFLIX, INC. AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NETFLIX OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ #include #include #include diff --git a/server/nf_callbacks.h b/server/nf_callbacks.h index 95b0648..a9626ee 100644 --- a/server/nf_callbacks.h +++ b/server/nf_callbacks.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Netflix, Inc. + * Copyright (c) 2014-2019 Netflix, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/server/system_callbacks.c b/server/system_callbacks.c index 9a2d14f..bc3555e 100644 --- a/server/system_callbacks.c +++ b/server/system_callbacks.c @@ -1,3 +1,27 @@ +/* + * Copyright (c) 2018-2019 Netflix, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETFLIX, INC. AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NETFLIX OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ #include #include #include "system_callbacks.h" diff --git a/server/system_callbacks.h b/server/system_callbacks.h index db3f369..3e585a3 100644 --- a/server/system_callbacks.h +++ b/server/system_callbacks.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Netflix, Inc. + * Copyright (c) 2018-2019 Netflix, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,6 +28,11 @@ #include "dial_server.h" +/** + * + * + * Sleep is the only supported action for 'system', and not implemented in this reference. + */ DIALStatus system_start(DIALServer *ds, const char *appname, const char *payload, const char* query_string, const char *additionalDataUrl, diff --git a/server/tests/test_dial_data.c b/server/tests/test_dial_data.c index bb6efd5..4fe6433 100644 --- a/server/tests/test_dial_data.c +++ b/server/tests/test_dial_data.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Netflix, Inc. + * Copyright (c) 2014-2019 Netflix, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/server/url_lib.c b/server/url_lib.c index 99d1d13..0dfa449 100644 --- a/server/url_lib.c +++ b/server/url_lib.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Netflix, Inc. + * Copyright (c) 2014-2019 Netflix, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -43,6 +43,16 @@ char* smartstrncpy(char* dest, char* src, size_t max_chars) { return dest; } +/** + * Convert a two-character hex representation into its ASCII equivalent + * and copy it into dest. + * + * @param dest the destination character buffer. + * @param a the first hex character. + * @param b the second hex character. + * @return 1 if the character was converted and copied, 0 if the hex + * characters are invalid. + */ static int append_char_from_hex(char* dest, char a, char b) { if ('a' <= a && a <= 'f') a = 10 + a - 'a'; diff --git a/server/url_lib.h b/server/url_lib.h index 537a790..d3fb30b 100644 --- a/server/url_lib.h +++ b/server/url_lib.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Netflix, Inc. + * Copyright (c) 2014-2019 Netflix, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,35 +31,94 @@ #include /** - * Concatenate a maxim of max_chars characters from src into dest, - * and return a pointer to the last character in dest. + * Copy a maximum of max_chars characters from src into dest, + * and return a pointer to the terminating NULL in dest. + * + * @param dest destination buffer. + * @param src string written into the destination buffer + * @param max_chars maximum number of characters to put into the destination + * buffer, excluding the trailing NULL. Must be less than or equal to + * the number of bytes available at dest - 1. + * @return a pointer to the end of the written string (the location of the + * terminating NULL). */ char* smartstrncpy(char* dest, char* src, size_t max_chars); +/** + * URL-unescape the source string into the destination string, up to the + * maximum number of destination characters. + * + * @param dst raw string buffer. + * @param src URL-escaped source string. + * @param max_size maximum number of characters to put into the destination + * buffer, excluding the trailing NULL. Must be less than or equal to + * sizeof(dst) - 1. + * @return the length of the raw string excluding the trailing NULL. Will be + * 0 if there were no characters to unescape or if the source string + * was malformed. + */ int urldecode(char *dst, const char *src, size_t max_size); +/** + * XML-escape the source string into the destination string, up to the maximum + * number of destination characters. + * + * @param dst XML-escaped string buffer. + * @param src raw source string. + * @param max_size maximum number of characters to put into the destination + * buffer, excluding the trailing NULL. Must be less than or equal to + * sizeof(dst) - 1. + * @return the length of the XML-escaped string excluding the trailing NULL. + */ void xmlencode(char *dst, const char *src, size_t max_size); /** - * Parse the value of the parameter with the given name from a query string. + * Return the value in the query string for the requested parameter name. + * + * @param query_string the URL query string. + * @param param_name the parameter name. + * @return the parameter value or NULL if out-of-memory. The caller must free + * the returned memory. */ char *parse_param(char *query_string, char *param_name); -/* - * Parse the application name out of a URI, such as /app/YouTube/dial_data. - * Note: this parser assumes that the dial_data url is of the form - * /apps//dial_data. If your DIAL server uses a different url-path, - * you will need to adapt the method below. +/** + * Parse the application name out of the full URI, for example + * /app/YouTube/dial_data. The application name identified as the string + * appearing before the last trailing slash, possibly prefixed with a slash, + * so /apps//dial_data and YouTube would be the application name in + * the previous example. + * + * If your DIAL server uses a different path format you will need to change + * this method to match. + * + * @param uri the URI, there must be a trailing slash. + * @return the application name, or "unknown" if two slashes cannot be found + * or the application name is zero-length, or NULL if out-of-memory. + * The caller must free the returned memory. */ char *parse_app_name(const char *uri); -/* - * Parse a list of DIALData params out of a query string. +/** + * Return a linked list of DIAL data constructed from the name/value parameter + * pairs of the provided query string. + * + * This function must be called while holding a mutex and is not itself + * thread-safe. + * + * @param query_string the URL query string. + * @return the DIAL data or NULL if there is none (e.g. parse error) or out-of- + * memory. The caller must free the returned memory. */ DIALData *parse_params(char * query_string); -/* Returns a url-encoded version of str */ -/* IMPORTANT: be sure to free() the returned string after use */ +/** + * Return the URL-escaped version of the provided string, which may be as + * large as 3x the size of the provided string, plus a trailing NULL byte. + * + * @return the URL-escaped version of the provided string. The caller must + * free the returned string. + */ char *url_encode(const char *str); #endif // URLLIB_H_