diff --git a/Makefile.am b/Makefile.am index c9ccb75e..f2d20713 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,11 +1,21 @@ SUBDIRS = man ARFLAGS = cr + +lib_pair_ap_a_CFLAGS = -Wall -g -DCONFIG_OPENSSL -pthread +lib_csrp_a_CFLAGS = -pthread +lib_tinyhttp_a_CFLAGS = -pthread lib_dbus_interface_a_CFLAGS = -pthread lib_mpris_interface_a_CFLAGS = -pthread bin_PROGRAMS = shairport-sync +BUILT_SOURCES = +noinst_HEADERS = +CLEANFILES = +shairport_sync_LDADD = +noinst_LIBRARIES = + # See below for the flags for the test client program shairport_sync_SOURCES = shairport.c rtsp.c mdns.c common.c rtp.c player.c alac.c audio.c loudness.c activity_monitor.c @@ -90,29 +100,47 @@ shairport_sync_SOURCES += mdns_dns_sd.c endif if USE_METADATA_HUB -shairport_sync_SOURCES += metadata_hub.c +shairport_sync_SOURCES += metadata_hub.c endif if USE_MQTT -shairport_sync_SOURCES += mqtt.c +shairport_sync_SOURCES += mqtt.c endif if USE_DACP_CLIENT -shairport_sync_SOURCES += dacp.c tinyhttp/chunk.c tinyhttp/header.c tinyhttp/http.c +shairport_sync_SOURCES += dacp.c +shairport_sync_LDADD += lib_tinyhttp.a +noinst_LIBRARIES += lib_tinyhttp.a +lib_tinyhttp_a_SOURCES = tinyhttp/chunk.c tinyhttp/header.c tinyhttp/http.c endif -BUILT_SOURCES = -noinst_HEADERS = -CLEANFILES = -shairport_sync_LDADD = -noinst_LIBRARIES = +if USE_AIRPLAY_2 +shairport_sync_SOURCES += ptp-utilities.c plist_xml_strings.c +shairport_sync_LDADD += lib_csrp.a lib_pair_ap.a +lib_pair_ap_a_SOURCES = pair_ap/pair.c pair_ap/pair_fruit.c pair_ap/pair_homekit.c pair_ap/pair-tlv.c +lib_csrp_a_SOURCES = csrp/srp.c +noinst_LIBRARIES += lib_pair_ap.a lib_csrp.a +plist_xml_strings.h: plists/get_info_response.xml + echo "// Do not edit!" > plist_xml_strings.h + echo "// This file is automatically generated from files in the plists folder." >> plist_xml_strings.h + echo "" >> plist_xml_strings.h + xxd -i plists/get_info_response.xml >> plist_xml_strings.h + echo "" >> plist_xml_strings.h +plist_xml_strings.c: plist_xml_strings.h + touch plist_xml_strings.c + +BUILT_SOURCES += plist_xml_strings.c plist_xml_strings.h +noinst_HEADERS += $(BUILT_SOURCES) +# Correctly clean the generated headers, but keep the xml description +CLEANFILES += $(BUILT_SOURCES) +endif if USE_DBUS shairport_sync_LDADD += lib_dbus_interface.a noinst_LIBRARIES += lib_dbus_interface.a lib_dbus_interface_a_SOURCES = dbus-interface.c shairport_sync_SOURCES += dbus-service.c -BUILT_SOURCES += dbus-interface.h dbus-interface.c +BUILT_SOURCES += dbus-interface.h dbus-interface.c # We don't want to install this header noinst_HEADERS += $(BUILT_SOURCES) # Correctly clean the generated headers, but keep the xml description @@ -203,7 +231,7 @@ if INSTALL_FREEBSD_SERVICE [ -e /var/run/shairport-sync ] || mkdir -p /var/run/shairport-sync chown shairport-sync:shairport-sync /var/run/shairport-sync [ -f /usr/local/etc/rc.d/shairport_sync ] || cp scripts/shairport-sync.freebsd /usr/local/etc/rc.d/shairport_sync - chmod 555 /usr/local/etc/rc.d/shairport_sync + chmod 555 /usr/local/etc/rc.d/shairport_sync endif if INSTALL_CYGWIN_SERVICE cp scripts/shairport-sync-config /usr/local/bin diff --git a/configure.ac b/configure.ac index 830c686a..79a08b4b 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.50]) -AC_INIT([shairport-sync], [3.3.8d7], [4265913+mikebrady@users.noreply.github.com]) +AC_INIT([shairport-sync], [4.0d0], [4265913+mikebrady@users.noreply.github.com]) AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR([shairport.c]) AC_CONFIG_HEADERS([config.h]) @@ -371,6 +371,21 @@ if test "x$REQUESTED_EXTENDED_METADATA_SUPPORT" = "x1" || test "x$with_metadata" fi AM_CONDITIONAL([USE_METADATA], [test "x$with_metadata" = "xyes"]) +# Look for AirPlay 2 flag +AC_ARG_WITH(airplay-2, [AS_HELP_STRING([--with-airplay-2],[Build for AirPlay 2])]) +if test "x$with_airplay_2" = "xyes" ; then + AC_DEFINE([CONFIG_AIRPLAY_2], 1, [Build for AirPlay 2]) + AC_MSG_RESULT(>>Include libraries required for AirPlay 2) + AC_CHECK_LIB([plist], [plist_from_memory], , AC_MSG_ERROR(AirPlay 2 support requires libplist -- libplist-dev suggested!)) + AC_CHECK_LIB([sodium], [sodium_init], ,[AC_MSG_ERROR([AirPlay 2 support requires libsodium -- libsodium-dev suggested])]) + AC_CHECK_LIB([avutil],[av_malloc], [], [AirPlay([Airplay 2 support requires libavutil -- libavutil-dev suggested])]) + AC_CHECK_LIB([avcodec],[avcodec_find_encoder], [], [AC_MSG_ERROR([AirPlay 2 support requires libavcodec -- libavcodec-dev suggested])]) + AC_CHECK_LIB([avformat],[avformat_new_stream], [], [AC_MSG_ERROR([AirPlay 2 support requires libavformat -- libavformat-dev suggested])]) + AC_CHECK_LIB([swresample],[swr_convert], [], [AC_MSG_ERROR([AirPlay 2 support requires libswresample -- libswresample-dev suggested])]) + AC_CHECK_LIB([uuid],[uuid_generate], [], [AC_MSG_ERROR([AirPlay 2 support requires the uuid library -- uuid-dev suggested])]) +fi +AM_CONDITIONAL([USE_AIRPLAY_2], [test "x$with_airplay_2" = "xyes"]) + if test "x${with_systemd}" = xyes ; then # Find systemd unit dir AC_ARG_WITH([systemdsystemunitdir], diff --git a/tinyhttp/LICENSE b/tinyhttp/LICENSE deleted file mode 100644 index ba420590..00000000 --- a/tinyhttp/LICENSE +++ /dev/null @@ -1,23 +0,0 @@ -Copyright 2012 Matthew Endsley -All rights reserved - -Redistribution and use in source and binary forms, with or without -modification, are permitted providing that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. 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 THE AUTHOR ``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 THE AUTHOR 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. diff --git a/tinyhttp/README.md b/tinyhttp/README.md deleted file mode 100644 index 367138f7..00000000 --- a/tinyhttp/README.md +++ /dev/null @@ -1,28 +0,0 @@ -tinyhttp -======== -Tiny (as in minimal) implementation of an HTTP response parser. The parser -itself is only dependent on: -* ` - tolower` -* ` - memcpy` - -For more information please see my blog post at: - -[![Build Status](https://api.travis-ci.org/mendsley/tinyhttp.png)](http://travis-ci.org/mendsley/tinyhttp) - -Contact -------- -[@MatthewEndsley](https://twitter.com/#!/MatthewEndsley) - - -License -------- -Copyright 2012 Matthew Endsley - -This project is governed by the BSD 2-clause license. For details see the file -titled LICENSE in the project root folder. - -Compiling ---------- -`gcc -c *.c && g++ -std=c++0x example.cpp *.o -o example` - -`./example` will fetch the root of diff --git a/tinyhttp/chunk.c b/tinyhttp/chunk.c deleted file mode 100644 index 3f7c889e..00000000 --- a/tinyhttp/chunk.c +++ /dev/null @@ -1,79 +0,0 @@ -/*- - * Copyright 2012 Matthew Endsley - * All rights reserved - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted providing that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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 THE AUTHOR ``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 THE AUTHOR 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. - */ - -static const unsigned char http_chunk_state[] = { -/* * LF CR HEX */ - 0xC1, 0xC1, 0xC1, 1, /* s0: initial hex char */ - 0xC1, 0xC1, 2, 0x81, /* s1: additional hex chars, followed by CR */ - 0xC1, 0x83, 0xC1, 0xC1, /* s2: trailing LF */ - 0xC1, 0xC1, 4, 0xC1, /* s3: CR after chunk block */ - 0xC1, 0xC0, 0xC1, 0xC1, /* s4: LF after chunk block */ -}; - -int http_parse_chunked(int* state, int *size, char ch) -{ - int newstate, code = 0; - switch (ch) { - case '\n': code = 1; break; - case '\r': code = 2; break; - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - case '8': case '9': case 'a': case 'b': - case 'c': case 'd': case 'e': case 'f': - case 'A': case 'B': case 'C': case 'D': - case 'E': case 'F': code = 3; break; - } - - newstate = http_chunk_state[*state * 4 + code]; - *state = (newstate & 0xF); - - switch (newstate) { - case 0xC0: - return *size != 0; - - case 0xC1: /* error */ - *size = -1; - return 0; - - case 0x01: /* initial char */ - *size = 0; - /* fallthrough */ - case 0x81: /* size char */ - if (ch >= 'a') - *size = *size * 16 + (ch - 'a' + 10); - else if (ch >= 'A') - *size = *size * 16 + (ch - 'A' + 10); - else - *size = *size * 16 + (ch - '0'); - break; - - case 0x83: - return *size == 0; - } - - return 1; -} - diff --git a/tinyhttp/chunk.h b/tinyhttp/chunk.h deleted file mode 100644 index e0df0600..00000000 --- a/tinyhttp/chunk.h +++ /dev/null @@ -1,48 +0,0 @@ -/*- - * Copyright 2012 Matthew Endsley - * All rights reserved - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted providing that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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 THE AUTHOR ``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 THE AUTHOR 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. - */ - -#ifndef HTTP_CHUNK_H -#define HTTP_CHUNK_H - -#if defined(__cplusplus) -extern "C" { -#endif - -/** - * Parses the size out of a chunk-encoded HTTP response. Returns non-zero if it - * needs more data. Returns zero success or error. When error: size == -1 On - * success, size = size of following chunk data excluding trailing \r\n. User is - * expected to process or otherwise seek past chunk data up to the trailing - * \r\n. The state parameter is used for internal state and should be - * initialized to zero the first call. - */ -int http_parse_chunked(int* state, int *size, char ch); - -#if defined(__cplusplus) -} -#endif - -#endif diff --git a/tinyhttp/example.cpp b/tinyhttp/example.cpp deleted file mode 100644 index 4054f9a7..00000000 --- a/tinyhttp/example.cpp +++ /dev/null @@ -1,190 +0,0 @@ -/*- - * Copyright 2012 Matthew Endsley - * All rights reserved - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted providing that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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 THE AUTHOR ``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 THE AUTHOR 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. - */ - - -/* -Compiling example: -$ g++ -o example example.cpp -*/ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "http.h" - -// directly embed the source here -extern "C" { - #include "http.c" - #include "header.c" - #include "chunk.c" -} - -// return a socket connected to a hostname, or -1 -int connectsocket(const char* host, int port) -{ - - addrinfo* result = NULL; - sockaddr_in addr = {0}; - int s; - - if (getaddrinfo(host, NULL, NULL, &result)) - goto error; - - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = INADDR_ANY; - for (addrinfo* ai = result; ai != NULL; ai = ai->ai_next) { - if (ai->ai_family != AF_INET) - continue; - - const sockaddr_in *ai_in = (const sockaddr_in*)ai->ai_addr; - addr.sin_addr = ai_in->sin_addr; - break; - } - - freeaddrinfo(result); - - if (addr.sin_addr.s_addr == INADDR_ANY) - goto error; - - s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (s == -1) - goto error; - - if (connect(s, (const sockaddr*)&addr, sizeof(addr))) - goto error; - - return s; - -error: - if (s != -1) - close(s); - if (result) - freeaddrinfo(result); - return -1; -} - -// Response data/funcs -struct HttpResponse { - std::vector body; - int code; -}; - -static void* response_realloc(void* opaque, void* ptr, int size) -{ - return realloc(ptr, size); -} - -static void response_body(void* opaque, const char* data, int size) -{ - HttpResponse* response = (HttpResponse*)opaque; - response->body.insert(response->body.end(), data, data + size); -} - -static void response_header(void* opaque, const char* ckey, int nkey, const char* cvalue, int nvalue) -{ /* example doesn't care about headers */ } - -static void response_code(void* opaque, int code) -{ - HttpResponse* response = (HttpResponse*)opaque; - response->code = code; -} - -static const http_funcs responseFuncs = { - response_realloc, - response_body, - response_header, - response_code, -}; - -int main() -{ - - int conn = connectsocket("nothings.org", 80); - if (conn < 0) { - fprintf(stderr, "Failed to connect socket\n"); - return -1; - } - - const char request[] = "GET / HTTP/1.0\r\nContent-Length: 0\r\n\r\n"; - int len = send(conn, request, sizeof(request) - 1, 0); - if (len != sizeof(request) - 1) { - fprintf(stderr, "Failed to send request\n"); - close(conn); - return -1; - } - - HttpResponse response; - response.code = 0; - - http_roundtripper rt; - http_init(&rt, responseFuncs, &response); - - bool needmore = true; - char buffer[1024]; - while (needmore) { - const char* data = buffer; - int ndata = recv(conn, buffer, sizeof(buffer), 0); - if (ndata <= 0) { - fprintf(stderr, "Error receiving data\n"); - http_free(&rt); - close(conn); - return -1; - } - - while (needmore && ndata) { - int read; - needmore = http_data(&rt, data, ndata, &read); - ndata -= read; - data += read; - } - } - - if (http_iserror(&rt)) { - fprintf(stderr, "Error parsing data\n"); - http_free(&rt); - close(conn); - return -1; - } - - http_free(&rt); - close(conn); - - printf("Response: %d\n", response.code); - if (!response.body.empty()) { - printf("%s\n", &response.body[0]); - } - - return 0; -} diff --git a/tinyhttp/header.c b/tinyhttp/header.c deleted file mode 100644 index cda9eb54..00000000 --- a/tinyhttp/header.c +++ /dev/null @@ -1,72 +0,0 @@ -/*- - * Copyright 2012 Matthew Endsley - * All rights reserved - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted providing that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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 THE AUTHOR ``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 THE AUTHOR 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 "header.h" - -static unsigned char http_header_state[] = { -/* * \t \n \r ' ' , : PAD */ - 0x80, 1, 0xC1, 0xC1, 1, 0x80, 0x80, 0xC1, /* state 0: HTTP version */ - 0x81, 2, 0xC1, 0xC1, 2, 1, 1, 0xC1, /* state 1: Response code */ - 0x82, 0x82, 4, 3, 0x82, 0x82, 0x82, 0xC1, /* state 2: Response reason */ - 0xC1, 0xC1, 4, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, /* state 3: HTTP version newline */ - 0x84, 0xC1, 0xC0, 5, 0xC1, 0xC1, 6, 0xC1, /* state 4: Start of header field */ - 0xC1, 0xC1, 0xC0, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, /* state 5: Last CR before end of header */ - 0x87, 6, 0xC1, 0xC1, 6, 0x87, 0x87, 0xC1, /* state 6: leading whitespace before header value */ - 0x87, 0x87, 0xC4, 10, 0x87, 0x88, 0x87, 0xC1, /* state 7: header field value */ - 0x87, 0x88, 6, 9, 0x88, 0x88, 0x87, 0xC1, /* state 8: Split value field value */ - 0xC1, 0xC1, 6, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, /* state 9: CR after split value field */ - 0xC1, 0xC1, 0xC4, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, /* state 10:CR after header value */ -}; - -int http_parse_header_char(int* state, char ch) -{ - int newstate, code = 0; - switch (ch) { - case '\t': code = 1; break; - case '\n': code = 2; break; - case '\r': code = 3; break; - case ' ': code = 4; break; - case ',': code = 5; break; - case ':': code = 6; break; - } - - newstate = http_header_state[*state * 8 + code]; - *state = (newstate & 0xF); - - switch (newstate) { - case 0xC0: return http_header_status_done; - case 0xC1: return http_header_status_done; - case 0xC4: return http_header_status_store_keyvalue; - case 0x80: return http_header_status_version_character; - case 0x81: return http_header_status_code_character; - case 0x82: return http_header_status_status_character; - case 0x84: return http_header_status_key_character; - case 0x87: return http_header_status_value_character; - case 0x88: return http_header_status_value_character; - } - - return http_header_status_continue; -} diff --git a/tinyhttp/header.h b/tinyhttp/header.h deleted file mode 100644 index 7f8ee6ab..00000000 --- a/tinyhttp/header.h +++ /dev/null @@ -1,61 +0,0 @@ -/*- - * Copyright 2012 Matthew Endsley - * All rights reserved - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted providing that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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 THE AUTHOR ``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 THE AUTHOR 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. - */ - -#ifndef HTTP_HEADER_H -#define HTTP_HEADER_H - -#if defined(__cplusplus) -extern "C" { -#endif - -enum http_header_status -{ - http_header_status_done, - http_header_status_continue, - http_header_status_version_character, - http_header_status_code_character, - http_header_status_status_character, - http_header_status_key_character, - http_header_status_value_character, - http_header_status_store_keyvalue -}; - -/** - * Parses a single character of an HTTP header stream. The state parameter is - * used as internal state and should be initialized to zero for the first call. - * Return value is a value from the http_header_status enuemeration specifying - * the semantics of the character. If an error is encountered, - * http_header_status_done will be returned with a non-zero state parameter. On - * success http_header_status_done is returned with the state parameter set to - * zero. - */ -int http_parse_header_char(int* state, char ch); - -#if defined(__cplusplus) -} -#endif - -#endif diff --git a/tinyhttp/http.c b/tinyhttp/http.c deleted file mode 100644 index 5ef0ae3f..00000000 --- a/tinyhttp/http.c +++ /dev/null @@ -1,227 +0,0 @@ -/*- - * Copyright 2012 Matthew Endsley - * All rights reserved - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted providing that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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 THE AUTHOR ``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 THE AUTHOR 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 "http.h" - -#include -#include - -#include "header.h" -#include "chunk.h" - -static void append_body(struct http_roundtripper* rt, const char* data, int ndata) -{ - rt->funcs.body(rt->opaque, data, ndata); -} - -static void grow_scratch(struct http_roundtripper* rt, int size) -{ - if (rt->nscratch >= size) - return; - - if (size < 64) - size = 64; - int nsize = (rt->nscratch * 3) / 2; - if (nsize < size) - nsize = size; - - rt->scratch = (char*)rt->funcs.realloc_scratch(rt->opaque, rt->scratch, nsize); - rt->nscratch = nsize; -} - -static int min(int a, int b) -{ - return a > b ? b : a; -} - -enum http_roundtripper_state { - http_roundtripper_header, - http_roundtripper_chunk_header, - http_roundtripper_chunk_data, - http_roundtripper_raw_data, - http_roundtripper_unknown_data, - http_roundtripper_close, - http_roundtripper_error, -}; - -void http_init(struct http_roundtripper* rt, struct http_funcs funcs, void* opaque) -{ - rt->funcs = funcs; - rt->scratch = 0; - rt->opaque = opaque; - rt->code = 0; - rt->parsestate = 0; - rt->contentlength = -1; - rt->state = http_roundtripper_header; - rt->nscratch = 0; - rt->nkey = 0; - rt->nvalue = 0; - rt->chunked = 0; -} - -void http_free(struct http_roundtripper* rt) -{ - if (rt->scratch) { - rt->funcs.realloc_scratch(rt->opaque, rt->scratch, 0); - rt->scratch = 0; - } -} - -int http_data(struct http_roundtripper* rt, const char* data, int size, int* read) -{ - const int initial_size = size; - while (size) { - switch (rt->state) { - case http_roundtripper_header: - switch (http_parse_header_char(&rt->parsestate, *data)) { - case http_header_status_done: - rt->funcs.code(rt->opaque, rt->code); - if (rt->parsestate != 0) - rt->state = http_roundtripper_error; - else if (rt->chunked) { - rt->contentlength = 0; - rt->state = http_roundtripper_chunk_header; - } else if (rt->contentlength == 0) - rt->state = http_roundtripper_close; - else if (rt->contentlength > 0) - rt->state = http_roundtripper_raw_data; - else if (rt->contentlength == -1) - rt->state = http_roundtripper_unknown_data; - else - rt->state = http_roundtripper_error; - break; - - case http_header_status_code_character: - rt->code = rt->code * 10 + *data - '0'; - break; - - case http_header_status_key_character: - grow_scratch(rt, rt->nkey + 1); - rt->scratch[rt->nkey] = tolower(*data); - ++rt->nkey; - break; - - case http_header_status_value_character: - grow_scratch(rt, rt->nkey + rt->nvalue + 1); - rt->scratch[rt->nkey+rt->nvalue] = *data; - ++rt->nvalue; - break; - - case http_header_status_store_keyvalue: - if (rt->nkey == 17 && 0 == strncmp(rt->scratch, "transfer-encoding", rt->nkey)) - rt->chunked = (rt->nvalue == 7 && 0 == strncmp(rt->scratch + rt->nkey, "chunked", rt->nvalue)); - else if (rt->nkey == 14 && 0 == strncmp(rt->scratch, "content-length", rt->nkey)) { - int ii, end; - rt->contentlength = 0; - for (ii = rt->nkey, end = rt->nkey + rt->nvalue; ii != end; ++ii) - rt->contentlength = rt->contentlength * 10 + rt->scratch[ii] - '0'; - } - - rt->funcs.header(rt->opaque, rt->scratch, rt->nkey, rt->scratch + rt->nkey, rt->nvalue); - - rt->nkey = 0; - rt->nvalue = 0; - break; - } - - --size; - ++data; - break; - - case http_roundtripper_chunk_header: - if (!http_parse_chunked(&rt->parsestate, &rt->contentlength, *data)) { - if (rt->contentlength == -1) - rt->state = http_roundtripper_error; - else if (rt->contentlength == 0) - rt->state = http_roundtripper_close; - else - rt->state = http_roundtripper_chunk_data; - } - - --size; - ++data; - break; - - case http_roundtripper_chunk_data: { - const int chunksize = min(size, rt->contentlength); - append_body(rt, data, chunksize); - rt->contentlength -= chunksize; - size -= chunksize; - data += chunksize; - - if (rt->contentlength == 0) { - rt->contentlength = 1; - rt->state = http_roundtripper_chunk_header; - } - } - break; - - case http_roundtripper_raw_data: { - const int chunksize = min(size, rt->contentlength); - append_body(rt, data, chunksize); - rt->contentlength -= chunksize; - size -= chunksize; - data += chunksize; - - if (rt->contentlength == 0) - rt->state = http_roundtripper_close; - } - break; - - case http_roundtripper_unknown_data: { - if (size == 0) - rt->state = http_roundtripper_close; - else { - append_body(rt, data, size); - size -= size; - data += size; - } - } - break; - - case http_roundtripper_close: - case http_roundtripper_error: - break; - } - - if (rt->state == http_roundtripper_error || rt->state == http_roundtripper_close) { - if (rt->scratch) { - rt->funcs.realloc_scratch(rt->opaque, rt->scratch, 0); - rt->scratch = 0; - } - *read = initial_size - size; - return 0; - } - } - - *read = initial_size - size; - return 1; -} - -int http_iserror(struct http_roundtripper* rt) -{ - return rt->state == http_roundtripper_error; -} diff --git a/tinyhttp/http.h b/tinyhttp/http.h deleted file mode 100644 index ba7e4cfb..00000000 --- a/tinyhttp/http.h +++ /dev/null @@ -1,93 +0,0 @@ -/*- - * Copyright 2012 Matthew Endsley - * All rights reserved - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted providing that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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 THE AUTHOR ``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 THE AUTHOR 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. - */ - -#ifndef HTTP_HTTP_H -#define HTTP_HTTP_H - -#if defined(__cplusplus) -extern "C" { -#endif - -/** - * Callbacks for handling response data. - * realloc_scratch - reallocate memory, cannot fail. There will only - * be one scratch buffer. Implemnentation may take - * advantage of this fact. - * body - handle HTTP response body data - * header - handle an HTTP header key/value pair - * code - handle the HTTP status code for the response - */ -struct http_funcs { - void* (*realloc_scratch)(void* opaque, void* ptr, int size); - void (*body)(void* opaque, const char* data, int size); - void (*header)(void* opaque, const char* key, int nkey, const char* value, int nvalue); - void (*code)(void* opqaue, int code); -}; - -struct http_roundtripper { - struct http_funcs funcs; - void *opaque; - char *scratch; - int code; - int parsestate; - int contentlength; - int state; - int nscratch; - int nkey; - int nvalue; - int chunked; -}; - -/** - * Initializes a rountripper with the specified response functions. This must - * be called before the rt object is used. - */ -void http_init(struct http_roundtripper* rt, struct http_funcs, void* opaque); - -/** - * Frees any scratch memory allocated during parsing. - */ -void http_free(struct http_roundtripper* rt); - -/** - * Parses a block of HTTP response data. Returns zero if the parser reached the - * end of the response, or an error was encountered. Use http_iserror to check - * for the presence of an error. Returns non-zero if more data is required for - * the response. - */ -int http_data(struct http_roundtripper* rt, const char* data, int size, int* read); - -/** - * Returns non-zero if a completed parser encounted an error. If http_data did - * not return non-zero, the results of this function are undefined. - */ -int http_iserror(struct http_roundtripper* rt); - -#if defined(__cplusplus) -} -#endif - -#endif