/*@@ @file Content.c @date Wed Sep 13 23:47:43 2000 @author Tom Goodale @desc The actual content of the web pages. Note that this need not be in this thorn, since it should just use the interface defined in http_Request.h and should never touch the internals. @enddesc @version $Header$ @@*/ #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include "cctk.h" #include "cctk_Parameter.h" #include "cctk_ActiveThorns.h" #include "util_String.h" #include "http_Request.h" #include "http_Auth.h" #include "http_Steer.h" #include "http_Cookies.h" #include "http_Content.h" #include "cctk_Arguments.h" #include "cctk_Parameters.h" static char *rcsid = "$Header$"; CCTK_FILEVERSION(DevThorns_httpd_Content_c) /******************************************************************** ********************* Local Data Types *********************** ********************************************************************/ struct httpStaticPage { char *page; unsigned int length; char *mime_type; }; struct httpLink { struct httpLink *next; char *URL; char *name; char *description; int flags; }; /******************************************************************** ********************* Local Routine Prototypes ********************* ********************************************************************/ static int RegisterImages(void); static int RegisterParameterPages(void); static int MainPage(cGH *cctkGH, httpRequest *request, void *data); static int AboutPage(cGH *cctkGH, httpRequest *request, void *data); static int MainParameterPage(cGH *cctkGH, httpRequest *request, void *data); static int ThornParameterPage(cGH *cctkGH, httpRequest *request, void *data); static int ShowStaticPage(cGH *cctkGH, httpRequest *request, void *data); static int CompareStrings(const void *string1, const void *string2); static int ControlPage(cGH *cctkGH, httpRequest *request, void *data); static int ControlSet(cGH *cctkGH, httpRequest *request); static int ControlTerminationPage(cGH *cctkGH, httpRequest *request); static int CookieTestPage(cGH *cctkGH, httpRequest *request, void *data); /******************************************************************** ********************* Other Routine Prototypes ********************* ********************************************************************/ int HTTPi_RegisterGroupsPages(void); /******************************************************************** ********************* Local Data ***************************** ********************************************************************/ static struct httpLink *ContentLinks = NULL; #define USER_LENGTH 255 /******************************************************************** ********************* External Routines ********************** ********************************************************************/ /*@@ @routine HTTP_ContentWork @date Sat Sep 16 15:22:59 2000 @author Tom Goodale @desc Does any work which needs to be done by the content pages. @enddesc @calls @calledby @history @endhistory @@*/ void HTTP_ContentWork(CCTK_ARGUMENTS) { #if 0 HTTP_SteerDispatch(); #endif } /*@@ @routine HTTP_RegisterPages @date Wed Sep 13 23:47:43 2000 @author Tom Goodale @desc Main page registration routine. @enddesc @calls @calledby @history @endhistory @@*/ int HTTP_RegisterPages(void) { DECLARE_CCTK_PARAMETERS #ifdef HTTP_DEBUG printf("Registering index.html\n"); #endif /* Register the master page. */ HTTP_RegisterPage("/index.html", MainPage, NULL); /* Register the server description page */ HTTP_RegisterPage("/About.html", AboutPage, NULL); /* Register parameter stuff */ RegisterParameterPages(); /* Register parameter control stuff. */ HTTP_RegisterPage("/control.html", ControlPage, NULL); HTTP_ContentLink("/control.html", "Cactus Control", "Control Panel for this run", HTTP_QUICKLINK); /* Register Groups Pages */ HTTPi_RegisterGroupsPages(); HTTP_AuthAddUser("user",user,password,encryption_scheme); /* Register images */ RegisterImages(); HTTP_RegisterPage("/cookies.html", CookieTestPage, NULL); return 0; } /*@@ @routine HTTP_ContentLink @date Sun Sep 17 13:17:56 2000 @author Tom Goodale @desc Register content links. @enddesc @calls @calledby @history @endhistory @@*/ int HTTP_ContentLink(const char *URL, const char *name, const char *description, int flags) { int retval; struct httpLink *link; struct httpLink *last; struct httpLink *current; link = (struct httpLink *)malloc(sizeof(struct httpLink)); if(link) { link->URL = Util_Strdup(URL); link->name = Util_Strdup(name); link->description = Util_Strdup(description); link->flags = flags; link->next = NULL; /* Put on list */ if(ContentLinks) { for(current=ContentLinks; current; current = current->next) { last = current; } last->next = link; } else { ContentLinks = link; } retval = 0; } else { retval = -1; } return retval; } /******************************************************************** ********************* Local Routines ************************* ********************************************************************/ /*@@ @routine CompareStrings @date Thu Sep 14 18:57:52 2000 @author Tom Goodale @desc Case independent string comparison to pass to qsort. @enddesc @calls @calledby @history @endhistory @@*/ static int CompareStrings(const void *string1, const void *string2) { return Util_StrCmpi(*(const char **)string1, *(const char **)string2); } /****************************************************************************** ***************************** Main Page ************************************** ******************************************************************************/ /*@@ @routine MainPage @date Wed Sep 13 23:47:43 2000 @author Tom Goodale @desc Displays the main page. @enddesc @calls @calledby @history @hdate Thu Sep 14 10:54:22 2000 @hauthor Tom Goodale @hdesc Copied content format from original http thorn developed by Werner Benger, with the aesthetic enhancements of Gabrielle Allen, John Shalf and Ed Seidel. @endhistory @@*/ static int MainPage(cGH *cctkGH, httpRequest *request, void *data) { int retval; int filelen; char message[4098]; struct httpLink *link; /* Status message */ strcpy(message,"HTTP/1.0 200 OK\r\n"); HTTP_Write(request, message, strlen(message)); /* Content-Type */ strcpy(message,"Content-Type: text/html\r\n\r\n"); HTTP_Write(request, message, strlen(message)); /* Start the page */ strcpy(message,"Running CACTUS Status Information\n"); HTTP_Write(request, message, strlen(message)); /* Write out the main header part */ HTTP_ContentHeader(1,4096,message); HTTP_Write(request, message, strlen(message)); strcpy(message, "

Simulation Home Page

"); /* ADD QUICK LINKS (e.g. FOR PALM) */ if(ContentLinks) { strcpy(message, "
Quick links: "); for(link = ContentLinks; link; link=link->next) { if(link->flags & HTTP_QUICKLINK) { sprintf(message, "%s[%s]", message, link->URL, link->name); } } strcat(message,"
\n
\n"); HTTP_Write(request, message, strlen(message)); } /* Some blurb */ strcpy(message, "
" "
" "

Simulation web server:

" "

This browser is connected to a Cactus simulation which " "contains a web server thorn. This thorn allows you to " "monitor the simulation, and view and change parameters

" "

Depending on which other thorns are active, there may " "be additional features available, such as the viewing and " "downloading of output files

"); HTTP_Write(request, message, strlen(message)); /*************************************************************************/ /* AVAILABLE OPTIONS */ if(ContentLinks) { strcpy(message, "

Available options:

\n" "
    \n"); for(link = ContentLinks; link; link=link->next) { sprintf(message, "%s
  • %s %s
  • \n", message, link->URL, link->name, link->description); } sprintf(message,"%s
\n",message); HTTP_Write(request, message, strlen(message)); } /* CONFIGURATION DETAILS */ sprintf(message, "

Configuration:

" "
  • Flesh version %s" "
  • \n" "
  • Code compiled on " __DATE__ " at "__TIME__ "
  • \n" , CCTK_FullVersion()); strcat(message,"
  • Parameter filename "); HTTP_Write(request, message, strlen(message)); filelen = CCTK_ParameterFilename(4098,message); HTTP_Write(request, message, filelen); strcpy(message,"\n"); HTTP_Write(request, message, strlen(message)); if (cctkGH) { if (CCTK_nProcs(cctkGH) == 1) { strcpy(message,"
  • Single processor run
  • "); } else { sprintf(message,"
  • Multiprocessor run on %d CPUs
  • ", CCTK_nProcs(cctkGH)); } HTTP_Write(request, message, strlen(message)); } strcpy(message,"
"); HTTP_Write(request, message, strlen(message)); /******************************************************************************/ /* NEW COLUMN */ strcpy(message, "
"); HTTP_Write(request, message, strlen(message)); /*******************************************************************************/ /* CURRENT STATE OF SIMULATION */ if (cctkGH) { sprintf(message, "

Current state:

" "
  • Physical time %f" " \n" "
  • Iteration number %d" "
  • \n", cctkGH->cctk_time, cctkGH->cctk_iteration); } else { strcpy(message, "
  • Current cactus time is unknown
  • \n"); } HTTP_Write(request, message, strlen(message)); strcpy(message, "
"); HTTP_Write(request, message, strlen(message)); /* LIST COMPILED THORNS */ { int i; int nthorns; const char **thorns; nthorns = CCTK_NumCompiledThorns(); thorns = (const char **)malloc(nthorns * sizeof(char *)); for(i=0; i < nthorns; i++) { thorns[i] = CCTK_CompiledThorn (i); } /* Sort the thorns */ qsort(thorns, nthorns, sizeof(char *), CompareStrings); strcpy(message, "

Compiled thorns:

" "

This list shows all thorns compiled into the executable, " "those thorns which have been activated in the parameter " "file for this simulation are shown in " "red

" "
    "); for(i=0; i < nthorns; i++) { strcat(message, "
  • "); if (CCTK_IsThornActive(thorns[i])) { sprintf(message,"%s %s \n", message, thorns[i]); } else { strcat(message, thorns[i]); } } strcat(message, "
"); free(thorns); } HTTP_Write(request, message, strlen(message)); /* Finish table started by blurb */ strcpy(message, "
"); HTTP_Write(request, message, strlen(message)); /* Write out the footer part. */ HTTP_ContentFooter(0,4096,message); retval = HTTP_Write(request, message, strlen(message)); /* retval = HTTP_Write(request, base_page, strlen(base_page)); */ return retval; } /****************************************************************************** ***************************** Parameter Pages ******************************** ******************************************************************************/ static int RegisterParameterPages(void) { int i; const char *thorn; char pagename[27+20]; /* Thorns have maximum length */ char *namecopy; /* Two ways to do this - can either just have one function * registered as /Parameters which then checks request->residual, * to see what the actual accessed page is, or can register a * main page and one for each thorn. * Choose the latter for the mo to keep functions smaller, and also * since the compiled thorn list is static at the moment. */ HTTP_RegisterPage("/Parameters/index.html", MainParameterPage, NULL); HTTP_ContentLink("/Parameters/index.html", "Parameters", "Parameter Information and Control", HTTP_QUICKLINK); for (i = 0; i < CCTK_NumCompiledThorns (); i++) { thorn = CCTK_CompiledThorn(i); sprintf(pagename,"/Parameters/%s", thorn); namecopy = Util_Strdup(thorn); HTTP_RegisterPage(pagename, ThornParameterPage, namecopy); } return 0; } /*@@ @routine MainParameterPage @date Wed Sep 13 23:47:43 2000 @author Tom Goodale @desc Displays the parameter page. @enddesc @calls @calledby @history @hdate Sat Sep 16 15:13:16 2000 @hauthor Tom Goodale @hdesc Copied content format from original http thorn developed by Werner Benger, with the aesthetic enhancements of Gabrielle Allen, John Shalf and Ed Seidel. @endhistory @@*/ static int MainParameterPage(cGH *cctkGH, httpRequest *request, void *data) { int retval; char message[4098]; int i; const char *thorn; /* Status message */ strcpy(message,"HTTP/1.0 200 OK\r\n"); HTTP_Write(request, message, strlen(message)); /* Content-Type */ strcpy(message,"Content-Type: text/html\r\n\r\n"); HTTP_Write(request, message, strlen(message)); /* Start the page */ strcpy(message, "Cactus Parameters Request\n"); HTTP_Write(request, message, strlen(message)); strcpy(message,"\n"); HTTP_Write(request, message, strlen(message)); HTTP_ContentHeader(0,4098,message); HTTP_Write(request, message, strlen(message)); strcpy(message, "
"); HTTP_Write(request, message, strlen(message)); strcpy(message, "

Check/Modify Parameters

\n" "

From this page you can check the values \n" "of all parameters for the \n" "simulation, and modify any parameters which have been designated as steerable

\n" "

Parameters can be viewed for all Active Thorns, that is, for thorns which \n" "have been activated in the parameter file for the simulation. \n" "Select one of the active thorns for this simulation from the list below to \n" "view all of its parameters

\n" "

Steerable parameters can be identified by the presence of a form input box, \n" "to change the value of a parameter, simply edit the value in the box and press \n" " the submit button to register the new values.

\n" "" "\n"); HTTP_Write(request, message, strlen(message)); for (i = 0; i < CCTK_NumCompiledThorns (); i++) { thorn = CCTK_CompiledThorn (i); if (CCTK_IsThornActive (thorn)) { sprintf(message, "\n" "", thorn, thorn,CCTK_ThornImplementation(thorn)); HTTP_Write(request, message, strlen(message)); } } strcpy(message,"
Thorn NameImplementation
%s%s
"); HTTP_Write(request, message, strlen(message)); /* Write out the footer part. */ HTTP_ContentFooter(0,4098,message); retval = HTTP_Write(request, message, strlen(message)); return retval; } static const char *notauthorized_page = "\nError 401: Not Authorized\ You are not authorized to access this page\n\n"; /*@@ @routine ThornParameterPage @date Sat Sep 16 15:13:55 2000 @author Tom Goodale @desc Parameter page for a thorn. Checks to see if it is a setting request or an info request and behaves accordingly. Copied content format from original http thorn developed by Werner Benger, with the aesthetic enhancements of Gabrielle Allen, John Shalf and Ed Seidel. @enddesc @calls @calledby @history @endhistory @@*/ static int ThornParameterPage(cGH *cctkGH, httpRequest *request, void *data) { int retval=0; char message[4098]; const char *thorn; int first; const cParamData *pData; char *value; const httpArg *argument; char user[USER_LENGTH+1]; int notauthorised; int readonly; int param_type; int param_bool; int nsteerable=0; int nfixed=0; thorn = (const char *)data; notauthorised = HTTP_AuthenticateBasic(request, "user", user, USER_LENGTH); readonly = notauthorised; if(request->n_arguments > 0) { /* This is a parameter set request */ if(!notauthorised) { if(!readonly) { /* Queue parameters for steering */ first = 1; while(argument = HTTP_ArgumentWalk(request, first)) { first = 0; fprintf(stderr, "Setting %s::%s to %s\n", thorn, argument->arg, argument->value); HTTP_SteerQueue(thorn, argument->arg, argument->value); } /* Now redirect the browser to the normal page */ /* Status message */ if(request->http_major_version < 1 || (request->http_major_version == 1 && request->http_minor_version < 1)) { /* Older browsers don't understand 303 */ strcpy(message,"HTTP/1.0 302 Found\r\n"); } else { strcpy(message,"HTTP/1.0 303 See Other\r\n"); } sprintf(message, "%sLocation: /Parameters/%s/\r\n\r\n", message, thorn); HTTP_Write(request, message, strlen(message)); } else { /* Redirect the browser to the normal page */ /* Status message */ if(request->http_major_version < 1 || (request->http_major_version == 1 && request->http_minor_version < 1)) { /* Older browsers don't understand 303 */ strcpy(message,"HTTP/1.0 302 Found\r\n"); } else { strcpy(message,"HTTP/1.0 303 See Other\r\n"); } sprintf(message, "%sLocation: /Parameters/%s/\r\n\r\n", message, thorn); HTTP_Write(request, message, strlen(message)); } } else { strcpy(message,"HTTP/1.0 401 Unauthorized\r\n"); HTTP_Write(request, message, strlen(message)); strcpy(message,"WWW-Authenticate: Basic realm=\"foo\"\r\n"); HTTP_Write(request, message, strlen(message)); strcpy(message,"Content-Type: text/html\r\n\r\n"); HTTP_Write(request, message, strlen(message)); HTTP_Write(request, notauthorized_page, strlen(notauthorized_page)); } } else { /* Display the page. */ /* Status message */ strcpy(message,"HTTP/1.0 200 OK\r\n"); HTTP_Write(request, message, strlen(message)); /* Content-Type */ strcpy(message,"Content-Type: text/html\r\n\r\n"); HTTP_Write(request, message, strlen(message)); /* Start the page */ sprintf(message, "Cactus Parameters Request : %s\n", thorn); HTTP_ContentHeader(0,4098,message); strcat(message,""); HTTP_Write(request, message, strlen(message)); if (!CCTK_IsThornActive(thorn)) { sprintf(message," Thorn %s is not active !!!
\n",thorn); HTTP_Write(request, message, strlen(message)); } else { /* Send table of available parameters for given thorn */ /* Steerable parameters can be edited in a FORM. */ sprintf(message, "

Check/Modify Parameters

" "

Thorn %s

\n", thorn); strcat(message, "

Parameters in Cactus can be either fixed or steerable. " "Steerable parameters are those which can be modified during a " "simulation" "To change steerable parameters, edit the values and press \n" " the submit button." "Before applying the new parameter value, Cactus will check that" " the parameter lies in the allowed range. Note that there" " is currently no log of parameters which have been modified.

\n" "

The tables below show the parameter name, current value and description." "The default value of each parameter is shown in brackets at the end of the description.

" "

View parameters from another thorn

\n"); HTTP_Write(request, message, strlen(message)); if(!readonly ) { sprintf(message,"
",thorn); HTTP_Write(request, message, strlen(message)); } /* Walk through all steerable parameters of given implementation. */ first = 1; while(CCTK_ParameterWalk(first, thorn, NULL, &pData) == 0) { first = 0; strcpy(message,""); value = CCTK_ParameterValString (pData->name, pData->thorn); if(value) { if (pData->steerable == CCTK_STEERABLE_ALWAYS && !readonly) { if (nsteerable == 0) { strcat(message,"

Steerable Parameters

" ""); } nsteerable++; if (pData->type == PARAMETER_BOOLEAN) { param_bool = *((CCTK_INT *)CCTK_ParameterGet(pData->name,thorn,¶m_type)); sprintf(message, "%s" "\n", message,pData->name,pData->name, param_bool ? "checked" : "", pData->name, param_bool ? "" : "checked",pData->description,pData->defval); } else { sprintf(message, "%s" "\n", message, pData->name, pData->name, value, pData->description,pData->defval); } } free (value); } HTTP_Write(request, message, strlen(message)); } if (nsteerable>0) { strcpy(message, "
%s" "Yes " "  No " "%s (%s)
%s" "" "%s (%s)
\n"); HTTP_Write(request, message, strlen(message)); } if(!readonly && nsteerable>0) { strcpy(message, "\n" "
\n"); HTTP_Write(request, message, strlen(message)); } /* Walk through non-all steerable parameters of given implementation. */ first = 1; while(CCTK_ParameterWalk(first, thorn, NULL, &pData) == 0) { first = 0; strcpy(message,""); value = CCTK_ParameterValString (pData->name, pData->thorn); if(value) { if (!(pData->steerable == CCTK_STEERABLE_ALWAYS && !readonly)) { if (nfixed == 0) { strcat(message,"

Fixed Parameters

" ""); } nfixed++; /* FIXME: This is a hack - should put in parameter tags. */ if(strcmp(thorn,CCTK_THORNSTRING) || (strcmp(pData->name,"user") && strcmp(pData->name,"password") && strcmp(pData->name,"encryption_scheme"))) { sprintf(message, "%s" "\n", message,pData->name, value, pData->description,pData->defval); } free(value); } } HTTP_Write(request, message, strlen(message)); } if (nfixed>0) { strcpy(message, "
%s%s%s (%s)
\n"); HTTP_Write(request, message, strlen(message)); } } strcpy(message,"
"); HTTP_Write(request, message, strlen(message)); /* Write out the footer part. */ HTTP_ContentFooter(0,4098,message); retval = HTTP_Write(request, message, strlen(message)); } /* n_arguments > 0 */ return retval; } /****************************************************************************** ***************************** Images ***************************************** ******************************************************************************/ #include "images/wwwcactuscodeorg.h" /*@@ @routine RegisterImages @date Wed Sep 13 23:47:43 2000 @author Tom Goodale @desc Registers images. Images are static pages, so it registers a function which takes a data structure and displays it. @enddesc @calls @calledby @history @endhistory @@*/ static int RegisterImages(void) { struct httpStaticPage *image; image = (struct httpStaticPage *)malloc(sizeof(struct httpStaticPage)); if(image) { image->page = (char *)malloc(sizeof(wwwcactuscodeorg)); memcpy(image->page, wwwcactuscodeorg, sizeof(wwwcactuscodeorg)); image->length = sizeof(wwwcactuscodeorg); image->mime_type = (char *)malloc(strlen("image/jpeg")+1); strcpy(image->mime_type, "image/jpeg"); #ifdef HTTP_DEBUG printf("Registering /Images/wwwcactuscodeorg.jpg\n"); #endif HTTP_RegisterPage("/Images/wwwcactuscodeorg.jpg", ShowStaticPage, (void *)image); } return 0; } /*@@ @routine ShowStaticPages @date Wed Sep 13 23:47:43 2000 @author Tom Goodale @desc Displays a static page. @enddesc @calls @calledby @history @endhistory @@*/ static int ShowStaticPage(cGH *cctkGH, httpRequest *request, void *data) { int retval; char message[1024]; struct httpStaticPage *page; if(data) { page = (struct httpStaticPage *)data; strcpy(message,"HTTP/1.0 200 OK\r\n"); HTTP_Write(request, message, strlen(message)); sprintf(message,"Content-Length: %d\r\nContent-Type: %s\r\n\r\n", page->length, page->mime_type); HTTP_Write(request, message, strlen(message)); retval = HTTP_Write(request, page->page, page->length); } else { retval = -1; } return retval; } /*@@ @routine ControlPage @date Sun Sep 17 14:37:59 2000 @author Tom Goodale @desc Cactus Control Panel @enddesc @calls @calledby @history @endhistory @@*/ static int ControlPage(cGH *cctkGH, httpRequest *request, void *data) { DECLARE_CCTK_PARAMETERS int retval; char message[4098]; int notauthorised; char thisuser[USER_LENGTH+1]; notauthorised = HTTP_AuthenticateBasic(request, "user", thisuser, USER_LENGTH); if(!notauthorised) { /* Ok the person is authorised. */ if(request->n_arguments == 0) { /* No arguments, so just display the page */ strcpy(message,"HTTP/1.0 200 Ok\r\n"); HTTP_Write(request, message, strlen(message)); strcpy(message,"WWW-Authenticate: Basic realm=\"Cactus Control\"\r\n"); HTTP_Write(request, message, strlen(message)); HTTP_CookieSend(request,"user", thisuser, "/", NULL, NULL, 0); strcpy(message,"Content-Type: text/html\r\n\r\n"); HTTP_Write(request, message, strlen(message)); /* Start the page */ strcpy(message, "Cactus Control and Status Page\n"); HTTP_ContentHeader(0,4098,message); strcat(message, "

Control and Status Page

"); HTTP_Write(request, message, strlen(message)); strcpy(message, "

This page is the control center for interacting with" " the current simulation. It is possible to steer certain" " parameters, as well as pause, restart, or terminate the" " simulation.

"); HTTP_Write(request, message, strlen(message)); strcpy(message, "
\n" "
\n" "\n" "\n"); HTTP_Write(request, message, strlen(message)); sprintf(message, "\n", pause ? "checked" : ""); HTTP_Write(request, message, strlen(message)); sprintf(message, "\n", pause ? "" : "checked"); HTTP_Write(request, message, strlen(message)); strcpy(message, "\n"); HTTP_Write(request, message, strlen(message)); strcpy(message, "
PAUSE
RUN
TERMINATE
\n" "\n" "\n" "\n" "
\n" "
\n" "
\n"); HTTP_Write(request, message, strlen(message)); /* Write out the footer part. */ HTTP_ContentFooter(0,4098,message); retval = HTTP_Write(request, message, strlen(message)); } else { /* Arguments, so control simulation */ ControlSet(cctkGH, request); } } else { /* Not authorised */ strcpy(message,"HTTP/1.0 401 Unauthorized\r\n"); HTTP_Write(request, message, strlen(message)); strcpy(message,"WWW-Authenticate: Basic realm=\"Cactus Control\"\r\n"); HTTP_Write(request, message, strlen(message)); HTTP_CookieCancel(request,"user", "/"); strcpy(message,"Content-Type: text/html\r\n\r\n"); HTTP_Write(request, message, strlen(message)); HTTP_Write(request, notauthorized_page, strlen(notauthorized_page)); } return 0; } /*@@ @routine ControlSet @date Sun Sep 17 14:39:50 2000 @author Tom Goodale @desc Set the status of the simulation based on the controls. @enddesc @calls @calledby @history @endhistory @@*/ static int ControlSet(cGH *cctkGH, httpRequest *request) { char message[4098]; const char *runstate; runstate = HTTP_ArgumentValue(request,"runstate"); switch(*runstate) { case 'T' : HTTP_SteerQueue(CCTK_THORNSTRING, "terminate", "yes"); ControlTerminationPage(cctkGH, request); break; case 'P' : HTTP_SteerQueue(CCTK_THORNSTRING, "pause", "yes"); break; case 'R' : HTTP_SteerQueue(CCTK_THORNSTRING, "pause", "no"); break; default : fprintf(stderr, "Unknown runstate '%s'\n", runstate); } /* Now redirect the browser to the normal page */ /* Status message */ if(request->http_major_version < 1 || (request->http_major_version == 1 && request->http_minor_version < 1)) { /* Older browsers don't understand 303 */ strcpy(message,"HTTP/1.0 302 Found\r\n"); } else { strcpy(message,"HTTP/1.0 303 See Other\r\n"); } sprintf(message, "%sLocation: /control.html/\r\n\r\n", message); HTTP_Write(request, message, strlen(message)); return 0; } /*@@ @routine ControlTerminationPage @date Sun Sep 17 14:40:16 2000 @author Tom Goodale @desc Page to be shown on termination of Cactus. @enddesc @calls @calledby @history @endhistory @@*/ static int ControlTerminationPage(cGH *cctkGH, httpRequest *request) { int retval; char message[4098]; /* Status message */ strcpy(message,"HTTP/1.0 200 OK\r\n"); HTTP_Write(request, message, strlen(message)); /* Content-Type */ strcpy(message,"Content-Type: text/html\r\n\r\n"); HTTP_Write(request, message, strlen(message)); /* Start the page */ strcpy(message,"Running CACTUS Status Information : Terminated\n"); HTTP_Write(request, message, strlen(message)); /* Write out the main header part */ HTTP_ContentHeader(1,4098,message); HTTP_Write(request, message, strlen(message)); strcpy(message, "

Simulation Home Page

"); HTTP_Write(request, message, strlen(message)); /* Some blurb */ strcpy(message, "
" "
" "

Simulation web server:

" "

This browser is connected to a Cactus simulation which contains " "a web server thorn. This thorn allows you to monitor the simulation, " "and view and change parameters

" "

Depending on which other thorns are active, there may be additional " "features available, such as the viewing and downloading of output files

"); HTTP_Write(request, message, strlen(message)); /* CONFIGURATION DETAILS */ sprintf(message, "

Configuration:

" "
  • Flesh version %s" "
  • \n" "
  • Code compiled on " __DATE__ " at "__TIME__ "
  • \n" ,CCTK_FullVersion()); HTTP_Write(request, message, strlen(message)); if (cctkGH) { if (CCTK_nProcs(cctkGH) == 1) { strcpy(message,"
  • Single processor run
  • "); } else { sprintf(message,"
  • Multiprocessor run on %d CPUs
  • ", CCTK_nProcs(cctkGH)); } HTTP_Write(request, message, strlen(message)); } strcpy(message,"
"); HTTP_Write(request, message, strlen(message)); /******************************************************************************/ /* NEW COLUMN */ strcpy(message, "
"); HTTP_Write(request, message, strlen(message)); /*******************************************************************************/ /* CURRENT STATE OF SIMULATION */ if (cctkGH) { sprintf(message, "

Current state:

" "
  • Physical time %f" " \n" "
  • Iteration number %d" "
  • \n", cctkGH->cctk_time, cctkGH->cctk_iteration); } else { strcpy(message, "
  • Current cactus state is unknown
  • \n"); } HTTP_Write(request, message, strlen(message)); strcpy(message, "
  • This Cactus run is over.
  • \n"); HTTP_Write(request, message, strlen(message)); strcpy(message, "
"); HTTP_Write(request, message, strlen(message)); /* LIST COMPILED THORNS */ { int i; int nthorns; const char **thorns; nthorns = CCTK_NumCompiledThorns(); thorns = (const char **)malloc(nthorns * sizeof(char *)); for(i=0; i < nthorns; i++) { thorns[i] = CCTK_CompiledThorn (i); } /* Sort the thorns */ qsort(thorns, nthorns, sizeof(char *), CompareStrings); strcpy(message, "

Compiled thorns:

" "

This list shows all thorns compiled into the executable, " "those thorns which have been activated in the parameter " "file for this simulation are shown in " "red

" "
    "); for(i=0; i < nthorns; i++) { strcat(message, "
  • "); if (CCTK_IsThornActive(thorns[i])) { sprintf(message,"%s %s \n", message, thorns[i]); } else { strcat(message, thorns[i]); } } strcat(message, "
"); free(thorns); } HTTP_Write(request, message, strlen(message)); /* Finish table started by blurb */ strcpy(message, "
"); HTTP_Write(request, message, strlen(message)); /* Write out the footer part. */ HTTP_ContentFooter(0,4098,message); retval = HTTP_Write(request, message, strlen(message)); /* retval = HTTP_Write(request, base_page, strlen(base_page)); */ return retval; } /*@@ @routine HTTP_ContentSendFromFile @date Sun Sep 17 17:35:57 2000 @author Tom Goodale @desc Reads data from the filedescriptor and sends it to the HTTP request. @enddesc @calls @calledby @history @endhistory @@*/ int HTTP_ContentSendFromFile(httpRequest *request, int filedes) { int bytes_sent; int n_bytes; char buffer[4098]; bytes_sent = 0; while((n_bytes = read(filedes, buffer,4098)) > 0) { HTTP_Write(request, buffer, n_bytes); bytes_sent += n_bytes; } if(n_bytes == -1) { bytes_sent = -bytes_sent; } return bytes_sent; } /*@@ @routine AboutPage @date Sun Sep 17 2000 @author Gabrielle Allen @desc Displays a page about the web server @enddesc @calls @calledby @@*/ static int AboutPage(cGH *cctkGH, httpRequest *request, void *data) { int retval; char message[4098]; /* Status message */ strcpy(message,"HTTP/1.0 200 OK\r\n"); HTTP_Write(request, message, strlen(message)); /* Content-Type */ strcpy(message,"Content-Type: text/html\r\n\r\n"); HTTP_Write(request, message, strlen(message)); /* Start the page */ strcpy(message, "About Cactus Server\n"); HTTP_ContentHeader(0,4098,message); strcat(message,""); HTTP_Write(request, message, strlen(message)); strcpy(message, "
"); HTTP_Write(request, message, strlen(message)); strcpy(message, "

About this Web Server

"); HTTP_Write(request, message, strlen(message)); strcpy(message, "

These web pages are served by a simulation " "which is using the Cactus Code and Computational ToolKit, " "a freely available, parallel, collaborative," " portable and " "modular programming environment for HPC.

" "

The HTTPD module, or thorn " "which is serving these pages" " can be added to any Cactus application to provide on-line " "monitoring and control of simulations from any web browser.

" "

This HTTPD server and thorn interface has been designed and " "and implemented by Tom Goodale, based on the original idea and " "implementation by Werner Benger.

"); retval = HTTP_Write(request, message, strlen(message)); strcpy(message, "

For more information about Cactus, visit our " "permanent home page at " "www.cactuscode.org

"); retval = HTTP_Write(request, message, strlen(message)); /* Write out the footer part. */ HTTP_ContentFooter(0,4098,message); retval = HTTP_Write(request, message, strlen(message)); return retval; } /*@@ @routine CookieTestPage @date Mon Sep 18 23:28:19 2000 @author Tom Goodale @desc Test and example page for cookies. This will disappear soon. @enddesc @calls @calledby @history @endhistory @@*/ static int CookieTestPage(cGH *cctkGH, httpRequest *request, void *data) { int retval; char message[4098]; struct httpuFileList *list; const char *value; char *value2; /* Status message */ strcpy(message,"HTTP/1.0 200 OK\r\n"); HTTP_Write(request, message, strlen(message)); /* Cookie */ HTTP_CookieSend(request, "user1", "foobar4", NULL,NULL,NULL,0); HTTP_CookieSend(request, "user2", "foobar3", NULL,NULL,NULL,0); HTTP_CookieSend(request, "user3", "foobar2", NULL,NULL,NULL,0); HTTP_CookieSend(request, "user4", "foobar1", NULL,NULL,NULL,0); strcpy(message,"Content-Type: text/html\r\n\r\n"); HTTP_Write(request, message, strlen(message)); /* Start the page */ strcpy(message, "Cookie Test\n"); HTTP_Write(request, message, strlen(message)); HTTP_ContentHeader(0,4098,message); HTTP_Write(request, message, strlen(message)); strcat(message, "

Cookie Test

"); HTTP_Write(request, message, strlen(message)); strcpy(message, "
"); HTTP_Write(request, message, strlen(message)); value = HTTP_HeaderValue(request, "Cookie"); sprintf(message, "

Cookie was '%s'

\n", value); HTTP_Write(request, message, strlen(message)); value2 = HTTP_CookieGet(request,"user3"); sprintf(message, "

Cookie from decoder was '%s'

\n", value2); free(value2); HTTP_Write(request, message, strlen(message)); strcpy(message,"
"); HTTP_Write(request, message, strlen(message)); /* Write out the footer part. */ HTTP_ContentFooter(0,4098,message); retval = HTTP_Write(request, message, strlen(message)); return retval; }