/***************************************************************************
 *
 * GConnHttp test
 *
 * Copyright (C) 2004  Tim-Philipp Müller
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 ***************************************************************************/

#define GNET_EXPERIMENTAL 1
#include "conn-http.h"

#include <stdlib.h>
#include <string.h>       

#undef CONN_HTTP_GTK_DEMO

#ifdef CONN_HTTP_GTK_DEMO
# include <errno.h>
# include <gtk/gtk.h>
# include <unistd.h>
#endif

static gboolean   verbose; /* FALSE */

/***************************************************************************
 *
 *   http_callback
 *
 *   Print some information along the way (not required)
 *
 ***************************************************************************/

static void
http_callback (GConnHttp *http, GConnHttpEvent *event, gpointer baz)
{
	if (!verbose)
		return;

	switch (event->type)
	{
		case GNET_CONN_HTTP_RESOLVED:
		{
			GConnHttpEventResolved *ev_resolved = (GConnHttpEventResolved*)event;
			if (ev_resolved->ia)
				g_print ("RESOLVED: %s\n\n", gnet_inetaddr_get_canonical_name(ev_resolved->ia));
			else
				g_print ("RESOLVED: FAILED TO RESOLVE HOSTNAME.\n");
		}
		break;

		case GNET_CONN_HTTP_RESPONSE:
		{
			GConnHttpEventResponse *ev_response = (GConnHttpEventResponse*)event;
			guint                   n;
			
			g_print("RESPONSE: %u\n", ev_response->response_code); 
			for (n = 0;  ev_response->header_fields[n] != NULL;  ++n)
			{
				g_print("HEADER: %s: %s\n", 
				        ev_response->header_fields[n], 
				        ev_response->header_values[n]);
			}
			g_print("\n");
		}
		break;
		
		case GNET_CONN_HTTP_DATA_PARTIAL:
		{
			GConnHttpEventData *ev_data = (GConnHttpEventData*)event;
			if (ev_data->content_length > 0)
				g_print("PARTIAL DATA: %" G_GUINT64_FORMAT " bytes (%.1f%%)\n", ev_data->data_received,
				        ((gfloat)ev_data->data_received/(gfloat)ev_data->content_length) * 100.0);
			else
				g_print("PARTIAL DATA: %" G_GUINT64_FORMAT " bytes (content length unknown)\n", 
				        ev_data->data_received);
		}
		break;
		
		case GNET_CONN_HTTP_DATA_COMPLETE:
		{
			GConnHttpEventData *ev_data = (GConnHttpEventData*)event;
			g_print("\n");
			g_print("COMPLETE:  %" G_GUINT64_FORMAT " bytes received.\n", ev_data->data_received);
		}
		break;

		case GNET_CONN_HTTP_REDIRECT:
		{
			GConnHttpEventRedirect *ev_redir = (GConnHttpEventRedirect*)event;
			if (!ev_redir->auto_redirect)
				g_print("REDIRECT: New location => '%s' (not automatic)\n", ev_redir->new_location);
			else
				g_print("REDIRECT: New location => '%s' (automatic)\n", ev_redir->new_location);
		}
		break;
		
		case GNET_CONN_HTTP_CONNECTED:
			g_print("CONNECTED\n");
			break;

		/* Internal GConnHttp error */
		case GNET_CONN_HTTP_ERROR:
		{
			GConnHttpEventError *ev_error = (GConnHttpEventError*)event;
			g_print("ERROR #%u: %s.\n", ev_error->code, ev_error->message);
		}
		break;
		
		case GNET_CONN_HTTP_TIMEOUT:
		{
			g_print("GNET_CONN_HTTP_TIMEOUT.\n");
		}
		break;
                
		default:
			g_assert_not_reached();
	}
}

/***************************************************************************
 *
 *   test_get
 *
 ***************************************************************************/

static gboolean
test_get (const gchar *uri)
{
	GConnHttp   *httpconn;
	gchar       *buf;
	gsize        len;
	
	httpconn = gnet_conn_http_new();

	g_print ("\n=====> Testing GET \n");
		
	if (!gnet_conn_http_set_uri (httpconn, uri))
		return FALSE;

	if (!gnet_conn_http_run (httpconn, http_callback, NULL))
	{
		g_print("\t * GET operation failed.\n");
		return FALSE;
	}
		
	gnet_conn_http_steal_buffer(httpconn, &buf, &len);
	
	g_print("\t * GET operation ok: received %u bytes.\n", (guint)len);

	gnet_conn_http_delete(httpconn);
	g_free(buf);
	
	return (len > 0);
}

/***************************************************************************
 *
 *   test_get_binary
 *
 ***************************************************************************/

static gboolean
test_get_binary (const gchar *uri)
{
	GConnHttp   *httpconn;
	gchar       *buf;
	gsize        len;
	
	httpconn = gnet_conn_http_new();

	g_print ("\n=====> Testing binary GET \n");
		
	if (!gnet_conn_http_set_uri (httpconn, uri))
		return FALSE;

	if (!gnet_conn_http_run (httpconn, NULL, NULL))
	{
		g_print("\t * GET operation failed.\n");
		return FALSE;
	}
	
	gnet_conn_http_steal_buffer(httpconn, &buf, &len);
	
	g_print("\t * GET operation ok: received %u bytes.\n", (guint)len);

#ifdef CONN_HTTP_GTK_DEMO
	if (1)
	{
		GtkWidget   *win, *img;
		gchar       *fn;
		gint         fd;
	
		/* write image data to temp file */
		fd = g_file_open_tmp(NULL, &fn, NULL);
		if (!fd)
		{
			g_print("Could not create temp file: %s\n", g_strerror(errno));
			return FALSE;
		}
		
		if (write(fd, buf, len) != len)
		{
			g_print("Could not write to temp file: %s\n", g_strerror(errno));
			return FALSE;
		}
		
		close(fd);
	
		gtk_init(0, NULL);
	
		win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
		img = gtk_image_new_from_file(fn);
		gtk_container_add(GTK_CONTAINER(win), img);
		gtk_widget_show_all(win);
		g_signal_connect(win, "delete-event", G_CALLBACK(gtk_main_quit), NULL);
	
		gtk_main();
		unlink(fn);
		g_free(fn);
		return TRUE;
	}

#else

	if (!buf || len < 8 || strncmp(buf, "\211PNG\r\n\032\n", 8) != 0)
	{
		g_print ("\t * missing PNG signature?!\n");
		return FALSE;
	}
	
	g_print ("\t * PNG signature ok\n");

	if (len < (8+(4+4)) || strncmp(buf+8+4, "IHDR", 4) != 0)
	{
		g_print ("\t * missing IHDR chunk?!\n");
		return FALSE;
	}
	
	g_print ("\t * image width x height = %u x %u\n",
	         GUINT32_FROM_BE(*((guint32*)(buf+8+4+4))),
	         GUINT32_FROM_BE(*((guint32*)(buf+8+4+4+4))));
	
#endif
	
	gnet_conn_http_delete(httpconn);
	g_free(buf);
	return TRUE;
}

/***************************************************************************
 *
 *   test_redirect
 *
 ***************************************************************************/

static gboolean
test_redirect (const gchar *uri)
{
	GConnHttp   *httpconn;
	gchar       *buf;
	gsize        len;
	
	httpconn = gnet_conn_http_new();

	g_print ("\n=====> Testing GET with redirect \n");
		
	if (!gnet_conn_http_set_uri (httpconn, uri))
		return FALSE;

	if (!gnet_conn_http_run (httpconn, http_callback, NULL))
	{
		g_print("\t * GET operation with redirect failed.\n");
		return FALSE;
	}
		
	gnet_conn_http_steal_buffer(httpconn, &buf, &len);
	
	g_print("\t * GET operation with redirect ok: received %u bytes.\n", (guint)len);
	
	gnet_conn_http_delete(httpconn);
	g_free(buf);
	
	return TRUE;
}

/***************************************************************************
 *
 *   test_simple_get
 *
 *   Tests gnet_http_get()
 *
 ***************************************************************************/

static gboolean
test_simple_get (const gchar *url)
{
	gboolean  ret;
	gchar    *buf = NULL;
	gsize     buflen = 0;
	guint     code = 0;                

	g_print ("\n=====> Testing gnet_conn_http_run(): \n");

	ret = gnet_http_get (url, &buf, &buflen, &code);
	
	if (ret == FALSE)
	{
		g_print("\t * gnet_http_get() failed (buflen = %u, code = %u).\n", buflen, code);
		return FALSE;                
	}
        
	g_print("\t * gnet_http_get() succeded (buflen = %u, code = %u).\n", buflen, code);
	
	return TRUE;
}

/***************************************************************************
 *
 *   test_post
 *
 ***************************************************************************/

static gboolean
test_post (const gchar *artist, const gchar *album)
{
	GConnHttp   *http;
	gchar       *postdata, *buf, *tag, *artist_esc, *album_esc;
	gsize        buflen;
	
	g_print ("\n=====> Testing POST \n");

	/* g_markup_printf_escaped() only exists in Glib-2.4 and later */
	artist_esc = g_markup_escape_text (artist, -1);
	album_esc = g_markup_escape_text (album, -1);
	postdata = g_strdup_printf (
	                "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
	                "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
	                " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""
	                " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"
	                "<soap:Body>"
	                "<q1:ArtistSearchRequest xmlns:q1=\"http://soap.amazon.com\">"
	                "<ArtistSearchRequest href=\"#id1\" />"
	                "</q1:ArtistSearchRequest>"
	                "<q2:ArtistRequest id=\"id1\" xsi:type=\"q2:ArtistRequest\" xmlns:q2=\"http://soap.amazon.com\">"
	                "<artist xsi:type=\"xsd:string\">%s</artist>" /* <----------- */
	                "<page xsi:type=\"xsd:string\">1</page>"
	                "<mode xsi:type=\"xsd:string\">music</mode>"
	                "<tag xsi:type=\"xsd:string\">webservices-20</tag>"
	                "<type xsi:type=\"xsd:string\">lite</type>"
	                "<devtag xsi:type=\"xsd:string\"></devtag>"
	                "<keywords xsi:type=\"xsd:string\">%s</keywords>" /* <----------- */
	                "</q2:ArtistRequest>"
	                "</soap:Body>"
	                "</soap:Envelope>",
	                artist_esc, album_esc);

	g_free (artist_esc);
	g_free (album_esc);

	http = gnet_conn_http_new();

	if (!gnet_conn_http_set_uri (http, "http://soap.amazon.com/onca/soap3"))
		return FALSE;

	if (!gnet_conn_http_set_method (http, GNET_CONN_HTTP_METHOD_POST, postdata, strlen(postdata)))
		return FALSE;

	if (!gnet_conn_http_set_header (http, "SOAPAction", 
	                                "\"http://soap.amazon.com\"", 
	                                GNET_CONN_HTTP_FLAG_SKIP_HEADER_CHECK))
	{
		g_printerr("gnet_conn_http_set_header(SOAPAction) failed.\n");
		return FALSE;
	}
	             
	if (!gnet_conn_http_set_header (http, "Content-Type", 
	                                "text/xml; charset=utf-8", 
	                                GNET_CONN_HTTP_FLAG_SKIP_HEADER_CHECK))
	{
		g_printerr("gnet_conn_http_set_header(Content-Type) failed.\n");
		return FALSE;
	}


	if (!gnet_conn_http_run (http, http_callback, postdata))
	{
		g_print("\t * POST operation failed.\n");
		return FALSE;
	}
	
	gnet_conn_http_steal_buffer(http, &buf, &buflen);
	g_print("\t * POST operation ok: received %u bytes.\n", (guint)buflen);
		
	tag = strstr(buf, "</ListPrice>");
	if (tag)
	{
		*tag = 0x00;
		while (tag > buf && *tag != '>')
			--tag;
		++tag;
	}
		
	if (tag && *tag == '$')
		g_print ("\t * %s, %s - CD Album: ListPrice = %s\n", artist, album, tag);
	else
		g_print ("\t * oops, could not find ListPrice for CD Album %s, %s in data returned :|\n", artist, album);

	gnet_conn_http_delete(http);
	g_free(postdata);
	g_free(buf);
	return TRUE;
}

/***************************************************************************
 *
 *   foo
 *
 *   Without this, the main loop doesn't want to get going ?!
 *
 ***************************************************************************/

static gboolean
foo (gpointer baz)
{
	return TRUE;
}


/***************************************************************************
 *
 *   main
 *
 ***************************************************************************/

int
main (int argc, char **argv)
{
	verbose = FALSE;

	/* DIRTY HACK. Kids, don't do this at home */
	if (argc > 1  &&  (strcmp(argv[1], "--verbose") == 0 || strcmp(argv[1],"-v") == 0))
	{
		verbose = TRUE;
		argc--;
		argv[1] = argv[2];
	}
        
	/* without this, the GLib mainloop 
	 * doesn't seem to get started?! */
	g_timeout_add(50, foo, NULL); 

	if (argc > 1)
	{
		gboolean ok;
		 
		ok = test_get(argv[1]);
	
		g_print ("------------------------------------------------------------\n");
		g_print ("GET (%s):  %s\n", argv[1], (ok) ? "OK" : "FAILED");
		g_print ("------------------------------------------------------------\n");
		
		g_assert (ok == TRUE);
        }
	else
	{
		gboolean  get_ok, binget_ok, post_ok, redir1_ok, redir2_ok, urlget_ok;
		
		get_ok = test_get("http://www.google.com");

		post_ok = test_post ("Massive Attack", "Blue Lines");
		
		binget_ok = test_get_binary ("http://www.gnetlibrary.org/gnet.png");

		/* Test redirect to different host */
		redir1_ok = test_redirect ("http://www.amazon.com");
	
		/* Test redirect to different URL on same host */
		redir2_ok = test_redirect ("http://sf.net");
                
		/* Test gnet_http_get() */
		urlget_ok = test_simple_get ("http://www.gnetlibrary.org/src/"); 

		g_print ("------------------------------------------------------------\n");
		g_print ("GET (html)                 %s\n", (get_ok)    ? "OK" : "FAILED");
		g_print ("GET (binary)               %s\n", (binget_ok) ? "OK" : "FAILED");
		g_print ("POST                       %s\n", (post_ok)   ? "OK" : "FAILED");
		g_print ("Redirect (same host)       %s\n", (redir1_ok) ? "OK" : "FAILED");
		g_print ("Redirect (different host)  %s\n", (redir2_ok) ? "OK" : "FAILED");
		g_print ("gnet_http_get()            %s\n", (urlget_ok) ? "OK" : "FAILED");
		g_print ("------------------------------------------------------------\n");
		
                g_assert (get_ok && binget_ok && post_ok && redir1_ok && redir2_ok && urlget_ok);
	}
		
	return EXIT_SUCCESS;
}



syntax highlighted by Code2HTML, v. 0.9.1