summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornicolas.dufresne@gmail.com <nicolas.dufresne@gmail.com@c587cffe-e639-0410-9787-d7902ae8ed56>2012-10-15 20:06:17 +0000
committernicolas.dufresne@gmail.com <nicolas.dufresne@gmail.com@c587cffe-e639-0410-9787-d7902ae8ed56>2012-10-15 20:06:17 +0000
commitef4214b36b625675023bc79b37e6a841bacd741e (patch)
treedb5e19b46b8d32a7263560c4151fd09f6e0cd8d0
parent8e8b48f4a8c86c400cede60b70dadef03756b6bf (diff)
downloadlibproxy-ef4214b36b625675023bc79b37e6a841bacd741e.tar.gz
Add HTTP client unit test
This should help in preventing regression that could lead to new security issues. This unit test only runs on Unix for now. git-svn-id: http://libproxy.googlecode.com/svn/trunk@861 c587cffe-e639-0410-9787-d7902ae8ed56
-rw-r--r--libproxy/test/CMakeLists.txt7
-rw-r--r--libproxy/test/get-pac-test.cpp258
2 files changed, 265 insertions, 0 deletions
diff --git a/libproxy/test/CMakeLists.txt b/libproxy/test/CMakeLists.txt
index 69543a4..8894425 100644
--- a/libproxy/test/CMakeLists.txt
+++ b/libproxy/test/CMakeLists.txt
@@ -17,3 +17,10 @@ if(WIN32)
target_link_libraries(url-encode ws2_32)
endif()
add_test(NAME url-encode COMMAND ${CMAKE_CURRENT_BINARY_DIR}/url-encode)
+
+# Get PAC
+if (NOT WIN32)
+add_executable(get-pac-test ${CMAKE_CURRENT_SOURCE_DIR}/get-pac-test.cpp ${PROJECT_SOURCE_DIR}/url.cpp)
+target_link_libraries(get-pac-test pthread)
+add_test(NAME get-pac-test COMMAND ${CMAKE_CURRENT_BINARY_DIR}/get-pac-test)
+endif()
diff --git a/libproxy/test/get-pac-test.cpp b/libproxy/test/get-pac-test.cpp
new file mode 100644
index 0000000..a61fc4b
--- /dev/null
+++ b/libproxy/test/get-pac-test.cpp
@@ -0,0 +1,258 @@
+#include <cassert>
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <string.h>
+#include <pthread.h>
+
+#include "url.hpp"
+
+using namespace libproxy;
+
+class TestServer {
+ public:
+ TestServer(in_port_t port)
+ : m_port(port)
+ ,m_sock(-1)
+
+ {
+ m_pipe[0] = -1;
+ m_pipe[1] = -1;
+ }
+
+ void start()
+ {
+ struct sockaddr_in addr = {0};
+ int ret;
+ int i = 1;
+
+ addr.sin_family = AF_INET;
+ inet_aton("127.0.0.1", &addr.sin_addr);
+ addr.sin_port = ntohs(m_port);
+
+ if (m_sock != -1)
+ return;
+
+ m_sock = socket(AF_INET, SOCK_STREAM, 0);
+ assert(m_sock > 0);
+
+ setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
+
+ ret = bind(m_sock, (sockaddr*)&addr, sizeof (struct sockaddr_in));
+ assert(!ret);
+
+ ret = listen(m_sock, 1);
+ assert(!ret);
+
+ ret = pipe(m_pipe);
+ assert(!ret);
+
+ ret = pthread_create(&m_thread, NULL, TestServer::server_thread, this);
+ assert(!ret);
+ }
+
+ void stop()
+ {
+ assert (write(m_pipe[1], (void*)"q", 1) == 1);
+ pthread_join (m_thread, NULL);
+ close(m_pipe[1]);
+ m_pipe[1] = -1;
+ close(m_sock);
+ m_sock = -1;
+ }
+
+ private:
+ static void * server_thread(void *data)
+ {
+ TestServer *server = (TestServer*)data;
+ while (server->loop()) {}
+ return NULL;
+ }
+
+ bool loop()
+ {
+ int ret;
+ fd_set fds;
+ struct sockaddr_in addr;
+ int lf_count = 0;
+ bool done = false;
+ char buffer[1024];
+ char *ptr;
+ int csock;
+ socklen_t len = sizeof (struct sockaddr_in);
+
+ FD_ZERO (&fds);
+ FD_SET (m_pipe[0], &fds);
+ FD_SET (m_sock, &fds);
+
+ memset(buffer, 0, 1024);
+
+ // Wait for connection
+ ret = select(max(m_pipe[0], m_sock) + 1, &fds, NULL, NULL, NULL);
+ assert(ret > 0);
+
+ if (FD_ISSET (m_pipe[0], &fds)) {
+ close(m_pipe[0]);
+ m_pipe[0] = -1;
+
+ return false;
+ }
+
+ csock = accept(m_sock, (sockaddr*) &addr, &len);
+ assert(csock > 0);
+
+ // Read request
+ ptr = buffer;
+ do {
+ ret = recv (csock, ptr, 1, 0);
+ if (ret <= 0)
+ goto done;
+
+ if (*ptr == '\n') {
+ lf_count++;
+ } else if (*ptr != '\r') {
+ lf_count = 0;
+ }
+
+ if (lf_count == 2)
+ done = true;
+
+ ptr++;
+ assert((int) (ptr - buffer) < 1024);
+ } while (!done);
+
+ if (strstr(buffer, "basic")) {
+ sendBasic(csock);
+ } else if (strstr(buffer, "truncated")) {
+ sendTruncated(csock);
+ } else if (strstr(buffer, "overflow")) {
+ sendOverflow(csock);
+ } else if (strstr(buffer, "chunked")) {
+ sendChunked(csock);
+ } else {
+ assert(!"Unsupported request");
+ }
+
+done:
+ close(csock);
+ return true;
+ }
+
+ void sendBasic(int csock)
+ {
+ int ret;
+ const char *basic =
+ "HTTP/1.1 200 OK\n" \
+ "Content-Type: text/plain\n" \
+ "Content-Length: 10\n" \
+ "\n" \
+ "0123456789";
+ ret = send(csock, (void*)basic, strlen(basic), 0);
+ assert(ret == strlen(basic));
+ shutdown(csock, SHUT_RDWR);
+ close(ret);
+ }
+
+ void sendTruncated(int csock)
+ {
+ int ret;
+ const char *basic =
+ "HTTP/1.1 200 OK\n" \
+ "Content-Type: text/plain\n" \
+ "Content-Length: 10\n" \
+ "\n" \
+ "01234";
+ ret = send(csock, (void*)basic, strlen(basic), 0);
+ assert(ret == strlen(basic));
+ shutdown(csock, SHUT_RDWR);
+ close(ret);
+ }
+
+ void sendOverflow(int csock)
+ {
+ int ret;
+ int size = 500000;
+ char *buf = new char[size];
+ memset(buf, 1, size);
+
+ const char *basic =
+ "HTTP/1.1 200 OK\n" \
+ "Content-Type: text/plain\n" \
+ "Content-Length: 500000\n" \
+ "\n";
+ ret = send(csock, (void*)basic, strlen(basic), 0);
+ assert(ret == strlen(basic));
+ ret = send(csock, (void*)buf, size, 0);
+ assert(ret != size);
+ delete[] buf;
+ shutdown(csock, SHUT_RDWR);
+ close(ret);
+ }
+
+ void sendChunked(int csock)
+ {
+ int ret;
+ const char *chunked =
+ "HTTP/1.1 200 OK\n" \
+ "Content-Type: text/plain\n" \
+ "Transfer-Encoding: chunked\n" \
+ "\n" \
+ "5\n" \
+ "01234" \
+ "\n" \
+ "5\n" \
+ "56789" \
+ "\n";
+ ret = send(csock, (void*)chunked, strlen(chunked), 0);
+ assert(ret == strlen(chunked));
+ shutdown(csock, SHUT_RDWR);
+ close(ret);
+ }
+
+ in_port_t m_port;
+ int m_sock;
+ int m_pipe[2];
+ pthread_t m_thread;
+};
+
+
+int main()
+{
+ TestServer server(1983);
+ int rtv = 0;
+ char *pac;
+
+ url basic("http://localhost:1983/basic.js");
+ url truncated("http://localhost:1983/truncated.js");
+ url overflow("http://localhost:1983/overflow.js");
+ url chunked("http://localhost:1983/chunked.js");
+
+ server.start();
+
+ pac = basic.get_pac();
+ assert(pac != NULL);
+ assert(strlen(pac) == 10);
+ assert(!strcmp("0123456789", pac));
+ delete[] pac;
+
+ pac = truncated.get_pac();
+ assert(pac == NULL);
+
+ pac = overflow.get_pac();
+ assert(pac == NULL);
+
+ pac = chunked.get_pac();
+ assert(pac != NULL);
+ assert(strlen(pac) == 10);
+ assert(!strcmp("0123456789", pac));
+ delete[] pac;
+
+ server.stop();
+
+ return 0;
+}