![]() |
![]() |
||||||
![]() |
|||||||
|
/*
*
* 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," OK.<br>\n");
else
Print(C," 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> |