Navigation
Home
gpl
danovitschwebcam
1.4
http.c








































http.c
   
   /*
    *
    * http.c - part of Danovitsch Webcam
    *
    * Copyright (C) 2001 by Daan Vreeken
    *
    * Published under the terms of the GNU Public License 2.0
    * (or any later version)
    *
    */
   
   
   
   #include <stdlib.h>
   #include <stdio.h>
   #include <string.h>
   #include <sys/time.h>
   
   
   #include "general.h"
   #include "webcam.h"
   #include "io.h"
   #include "capture.h"
   #include "compress.h"
   #include "server.h"
   #include "http.h"
   
   
   
   
   
   
   char *HTTP_GetPostData(struct Connection *C, char *Name)
   {
   	int		Len = strlen(Name);
   	char		*Ptr = C->PostData;
   	char		*Ptr2;
   	char		*MaxPtr = C->PostData + C->PostLength;
   	char		*Arr;
   	int		Result;
   
   	while ((Ptr<MaxPtr) && (Result=strncmp(Name,Ptr,Len)))
   		Ptr++;
   
   	if (!Result)
   	{
   		Ptr+=Len;
   		Ptr2=Ptr;
   
   		while ((Ptr2<MaxPtr) && (*Ptr2!='&'))
   			Ptr2++;
   
   		//don't forget the null-terminating byte!
   		Len=Ptr2-Ptr+1;
   		Arr=(char *)malloc(Ptr2-Ptr);
   
   		if (Arr==NULL)
   		{
   			Error("Could not allocate HTTP_GetPostData buffer!");
   			return NULL;
   		}
   		
   
   		memcpy(Arr,Ptr,Len-1);
   		*(Arr+Len-1)=0;
   
   		return Arr;
   	}
   
   	return NULL;
   }
   
   
   
   void HTTP_SpitoutSettings(struct Connection *C) {
   
   	struct Capture_SettingsArr	*Arr = &Capture_Settings[0];
   	struct Capture_TextTable	*Text;
   			
   		
   	Print(C,"<br><br>\n");
   		
   	Print(C,"<table border=1 cellpadding=2 cellspacing=2 bgcolor=#e0e0e0>\n");
   	Print(C," <tr bgcolor=#c0c0ff><td>Name</td><td>Value</td><td>Range</td></tr>\n");
   	
   	while (Arr->ID!=NoID) {
   		
   		Print (C," <tr>\n");
   		PrintF(C,"  <td>%s</td>\n",Arr->Name);
   		Print (C,"  <td>\n");
   		Print (C,"   <form action='settings' method=POST>\n");
   			
   		switch (Arr->Type) {
   		case Type_Number:
   			PrintF(C,"    <input name='Setting' value='%s' type=hidden>\n",Arr->Name);
   			PrintF(C,"    <input name='Value' value='%d'>\n",Arr->NumValue);
   			PrintF(C,"    <input type=submit value='Set'>\n");
   			break;
   			
   		case Type_Text:
   			PrintF(C,"    <input name='Setting' value='%s' type=hidden>\n",Arr->Name);
   			PrintF(C,"    <select name='Value' width=100%>\n");
   
   			Text=Capture_SettingText;			
   			while ((Text->ID!=Arr->ID) && (Text->ID!=NoID))
   				Text++;
   				
   			while ((Text->ID==Arr->ID) && (Text->ID!=NoID)) {
   				
   				if (!strcmp(Arr->TxtValue,Text->Text))
   					PrintF(C,"     <option selected value='%s'>%s</option>\n",Text->Text,Text->Text);
   				else
   					PrintF(C,"     <option value='%s'>%s</option>\n",Text->Text,Text->Text);
   				Text++;
   			}
   			
   			Print (C,"    </select>\n");
   			PrintF(C,"    <input type=submit value='Set'>\n");
   			break;
   		}
   		PrintF(C,"   </form>\n");
   		PrintF(C,"  </td>\n");
   			
   		if (Arr->Type==Type_Number) {
   			PrintF(C,"  <td>%d - %d</td>\n",Arr->MinVal,Arr->MaxVal);
   		} else {
   			Print(C,"  <td>N/A</td>\n");
   		}
   			
   		Print (C," </tr>\n");
   		Arr++;
   	}
   		
   	Print(C,"</table>\n");
   	Print(C,"<br><br>Moo,<br>]:8)<br>\n");
   }
   
   
   
   void HTTP_SpitoutFooter(struct Connection *C) {
   
   	Print(C,"<br>\n");
   	Print(C,"<a href='/'>Return to the main page...</a><br>\n");
   	Print(C,"<br><br><br>\n");
   	Print(C,"</body>\n");
   	Print(C,"</html>\n");
   }
   
   
   
   void HTTP_FileSettings(struct Connection *C, char *FileName) {
   	char		*Setting;
   	char		*TxtValue;
   	char		*RedirectValue;
   	int		NumValue;
   	struct Capture_SettingsArr	*Arr = &Capture_Settings[0];
   
   
   	//try to set the settings...
   	Setting=HTTP_GetPostData(C,"Setting=");
   	TxtValue=HTTP_GetPostData(C,"Value=");
   	RedirectValue=HTTP_GetPostData(C,"Redirect=");
   
   	//spitout header
   	Print(C,"<html>\n");
   	
   	if (RedirectValue!=NULL) {
   		// This could be used to set a setting and then immediately redirect to another URL
   		// simply add a hidden input field named 'Redirect' with the URL as it's value
   		//
   		Print(C,"<meta http-equiv=\"Refresh\" content=\"0; url=http://gate.danovitsch.dnsq.org/cgi-bin/lamp.cgi\">\n");
   		free(RedirectValue);
   	}
   	Print(C,"<body bgcolor=\"#ffffff\">\n");
   
   	Print(C,"<center><h1>Settings interface</h1></center><br>\n");
   	Print(C,"<br><br>\n");
   
   	//check for missing stuff...
   	if ((Setting==NULL) || (TxtValue==NULL)) {
   		//Hmmm... no setting to set, let's spit out a list of settings...
   
   		if (Setting!=NULL)
   			free(Setting);
   		if (TxtValue!=NULL)
   			free(TxtValue);
   
   		HTTP_SpitoutSettings(C);
   		HTTP_SpitoutFooter(C);
   		return;
   	}
   
   	//just try to convert to a number
   	sscanf(TxtValue,"%d",&NumValue);
   
   	//lookup the setting
   	while ((Arr->ID!=NoID) && (strcasecmp(Arr->Name,Setting)))
   		Arr++;
   
   	//try setting it...
   	if (Arr->ID!=NoID) {
   		PrintF(C,"Trying to set '%s' to '%s'...<br>\n",Setting,TxtValue);
   		if (Capture_Set(Arr,Setting,NumValue,TxtValue))
   			Print(C,"&nbsp;OK.<br>\n");
   		else
   			Print(C,"&nbsp;failed!<br>\n");
   	} else {
   		Print(C,"Unknown setting!<br>\n");
   		Print(C,Setting);
   		Print(C,"<br>\n");
   	}
   
   	//list all settings
   	HTTP_SpitoutSettings(C);
   	
   	//page footer
   	HTTP_SpitoutFooter(C);
   
   	free(Setting);
   	free(TxtValue);
   }
   
   
   
   void HTTP_FileStats(struct Connection *C, char *FileName)
   {
   	int		Cnt;
   	int		State;
   	struct Capture_SettingsArr	*Setting = &Capture_Settings[0];
   
   
   	Debug(40,"Spitting out some stats...");
   
   	//page header
   	Print(C,"                Stats page\n");
   	Print(C,"\n\n");
   
   	//stats info
   	PrintF(C,"Server name          : %s\n",Server_String);
   	Print(C,"\n");
   	PrintF(C,"Active connections   : %d\n",Clients);
   	Print(C,"\n");
   
   	//connection state(s)
   	Print(C,"Connection state(s)  :\n");
   	for (Cnt=0; Cnt<Clients; Cnt++)
   	{
   		State=Client[Cnt].State;
   		PrintF(C," %-20d: %s",Cnt,StateName[State]);
   		if (&Client[Cnt]==C)
   			Print(C," <- that's me :)");
   		Print(C,"\n");
   	}
   	Print(C,"\n");
   
   	//image counter (total & since last restart)
   	PrintF(C,"Total images served  : %ld\n",ImagesServed);
   	PrintF(C,"Since last restart   : %ld\n",ImagesSinceRestart);
   	Print(C,"\n");
   
   	//capture settings
   	Print(C,"Capture settings     :\n");
   	while (Setting->ID!=NoID)
   	{
   		PrintF(C," %-20s: ",(char *)Setting->Name);
   
   		switch (Setting->Type)
   		{
   		case Type_Number:
   			PrintF(C,"%d",Setting->NumValue);
   			break;
   		case Type_Text:
   			PrintF(C,Setting->TxtValue);
   			break;
   		default:
   			Print(C,"Hugh?");
   		}
   		Print(C,"\n");
   
   		Setting++;
   	}
   	Print(C,"\n");
   	
   	//page footer
   	Print(C,"Moo,\n]:8)\n");
   }
   
   
   
   void HTTP_FileWebcam(struct Connection *C, char *FileName)
   {
   	char		*Ptr;
   	int		Position = 0;
   	int		Size = JPEGSize;
   
   	Error("Someone wants an image\x07");
   
   	//Should we fetch a new image?
   	if (TooOld(&JPEGTime,JPEGTimeout))
   	{
   		Debug(120,"Creating new JPEG image...");
   		Compress_CreateJPEG();
   		Size=JPEGSize;
   
   		gettimeofday(&JPEGTime,NULL);
   	}
   
   	Debug(90,"Sending: %d bytes",Size);
   
   	//Dump image...
   	Ptr=JPEGBuffer;
   	if (JPEGBuffer!=NULL)
   		while (Size>0)
   		{
   			if (Size>1000)
   				Size-=SockSend(C,Ptr,1000);
   			else
   				Size-=SockSend(C,Ptr,Size);
   			Ptr+=1000;
   		}
   
   	//let's count this one (unless it's /live/nocount.jpg)
   	if (strcmp(FileName,"/live/nocount.jpg"))
   		ImagesServed++;
   	
   	CountedImages++;
   	ImagesSinceRestart++;
   }
   
   
   
   void HTTP_FileRoot (struct Connection *C, char *FileName) {
   
   	Print (C,"<html>\n");
   	PrintF(C,"<head>\n");
   	PrintF(C," <title>%d</title>\n",Server_String);
   	PrintF(C," <meta http-equiv='Refresh' content='%d'>\n",PageReloadInterval);
   	Print (C,"</head>\n");
   	
   	Print (C,"<body bgcolor=#ffffff>\n");
   	PrintF(C,"<center><h1>%s</h1></center><br>\n",Server_String);
   	Print (C,"<br><br>\n");
   	
   	Print (C,"<img src='/live/webcam.jpg' alt='Live image'><br>\n");
   	Print (C,"<br><br><br>\n");
   	
   	Print (C,"</body>\n");
   	Print (C,"</html>\n");
   }
   
   
   
   struct HTTP_ResponseArr	HTTP_Responses[] = {
   	{200,"HTTP/1.1 200 OK",0,""},
   	{404,"HTTP/1.1 404 File not found",1,"<html><body><b>Error:</b><br>File not found</body></html>"},
   	{501,"HTTP/1.1 501 Method Not Implemented",1,"<html><body><b>Error:</b><br>Method not implemented</body></html>"},
   	{0,"",0,""}};
   
   
   
   struct HTTP_FileArr	HTTP_Files[] = {
   	{"/","text/html",&HTTP_FileRoot},
   	{"/live/webcam.jpg","image/jpeg",&HTTP_FileWebcam},
   	{"/live/nocount.jpg","image/jpeg",&HTTP_FileWebcam},
   //
   /// /live/nocount.jpg gives exactly the same output as /live/webcam.jpg,
   //  but the image-counter isn't updated...
   //
   	{"/cgi-bin/stats","text/plain",&HTTP_FileStats},
   	{"/cgi-bin/settings","text/html",&HTTP_FileSettings},
   	{NULL,NULL,NULL}};
   
   
   
   
   void HTTP_Header(struct Connection *C, int Code, char *ContentType)
   {
   	struct HTTP_ResponseArr	*Response = &HTTP_Responses[0];
   
   
   	//search for the header code
   	while ((Response->Code!=Code) && (Response->Code!=0))
   		Response++;
   
   	if (Response->Code==0)
   	{
   		Error("HUGH?! Got wrong HTTP code (%d)",Code);
   		return;
   	}
   	
   
   	///Spitout the header
   	PrintF(C,"%s\n",Response->Header);
   
   	//Server strings...
   	PrintF(C,"Server: %s\n",Server_String);
   	Print(C,"Cache-Control: no-cache\n");
   	Print(C,"Connection: close\n");
   	Print(C,"Pragma: no-cache\n");
   	
   	//Spitout content-type?
   	if (ContentType!=NULL)
   		PrintF(C,"Content-type: %s\n",ContentType);
   	
   	//Spitout an error document?
   	if (Response->IsError)
   	{
   		Error("HTTP error: %s",Response->Header);
   
   		Print(C,"Content-type: text/html\n");
   		Print(C,"\n");
   
   		Print(C,Response->ErrorDocument);
   		return;
   	}
   
   	Print(C,"\n");
   }
   
   
   
   void HTTP_Response(struct Connection *C)
   {
   	char			URLPart[8];
   	char			*FileName;
   	struct HTTP_FileArr	*File = &HTTP_Files[0];
   
   
   	//cut off the 'http://foo.bar' piece (if it's there)
   	strncpy((char *)&URLPart,C->RequestArg[1],8);
   	URLPart[7]=0;
   	if (!strcasecmp((char *)&URLPart,"http://"))
   	{
   		if (index(C->RequestArg[1]+8,'/')==NULL)
   		{
   			HTTP_Header(C,404,NULL);
   			return;
   		}
   		else
   			FileName=index(C->RequestArg[1]+8,'/');
   	}
   	else
   		FileName=C->RequestArg[1];
   
   	//little hack to cut off question marks '?' behind a filename...
   	if (index(FileName,'?')!=NULL)
   		*index(FileName,'?')=0;
   
   	Debug(60,"Requested file: %s",FileName);
   
   	//search for the file...
   	while ((File->Name!=NULL) && (strcmp(File->Name,FileName)))
   		File++;
   
   	//give a 404 if we don't have it
   	if (File->Name==NULL)
   	{
   		HTTP_Header(C,404,NULL);
   		return;
   	}
   
   
   	Debug(50,"Request OK. sending data...");
   
   	HTTP_Header(C,200,(char *)File->ContentType);
   
   	if (File->Handler!=NULL)
   		File->Handler(C,FileName);
   }
   
   
   
   
   

syntax highlighted by Code2HTML, v. 0.9.1


Email me with questions/comments : Daan <Danovitsch @ Vitsch . net>