dbb0850c7935dec65d3394ef1ddcdc10dafac5cf
braney
Tue Aug 18 10:03:38 2026 -0700
cheapcgi: parse %hh escapes directly instead of with sscanf, refs #37262
cgiDecode and cgiDecodeFull read each %hh escape with sscanf(in, "%2x", &code).
glibc builds a stream over the whole remaining string on every sscanf call, so
each call scans to the terminating null. That makes the cost of a decode
quadratic in the length of one variable's value.
The cost is real on data we already have. A saved session in hgcentraltest
holds a single 699 KB hgFind.matches value with 58,930 escapes; decoding it
takes 0.29 s of CPU, and cart.c loadHash does it on every load of that session.
The database cart has no size cap, so this is not bounded by the 1 MB limit on
request input that went in for #37452. At that 1 MB limit a single request
still costs over 2 s.
Reading the two hex digits directly is a few hundred times faster (430x on the
699 KB value) and never walks past them. Behavior is unchanged for well-formed
input: verified byte-identical over the top 200 carts of namedSessionDb,
sessionDb and userDb (2.4 million values, 14.7 MB), over an exhaustive sweep of
every "%" plus two arbitrary bytes, and over cgiEncode/cgiDecode round trips of
all 256 byte values.
Decoding now differs only where a "%" is not followed by two hex digits, which
nothing legitimate produces - none of the 659,624 escapes in those carts are
malformed. The old code was worse there anyway: sscanf skips leading
whitespace, so "% 0Z" decoded to a null byte in the middle of the value and
silently truncated it. Malformed escapes now yield '?' like other bad input.
Also removes the FAST_CGI_DECODE ifdef added earlier on this ticket. It never
touched cgiDecode, so it does not describe anything now that the real cost is
fixed. Its per-variable caps are superseded by the total input cap from
#37452, which aborts with a message rather than dropping a variable silently,
and cgiParseNext's variant silently skipped oversized variables for the
ENCODE/CIRM tag tools that are its only callers.
diff --git src/inc/cheapcgi.h src/inc/cheapcgi.h
index d0f3124b87f..8c24bed5668 100644
--- src/inc/cheapcgi.h
+++ src/inc/cheapcgi.h
@@ -1,711 +1,702 @@
/* cheapcgi.h - turns variables passed from the web form into
* something that C understands.
*
* This file is copyright 2000 Jim Kent, but license is hereby
* granted for all use - public, private or commercial. */
#ifndef CHEAPCGI_H
#define CHEAPCGI_H
#include "dystring.h"
#ifndef HASH_H
#include "hash.h"
#endif
-// #define FAST_CGI_DECODE
-#ifdef FAST_CGI_DECODE
-// 50kB per-variable limit on content length to prevent egregious
-// cart-stuffing, whether intentional or accidental. 5kB limit
-// on variable names for similar reasons.
-#define CGI_VAR_SIZE_LIMIT 50000
-#define CGI_VAR_NAME_LIMIT 5000
-#endif
-
//============ javascript inline-separation routines ===============
void jsInlineFinish();
/* finish outputting accumulated inline javascript */
void jsInline(char *javascript);
/* Add text to output file or memory structure */
void jsInlineF(char *format, ...)
/* Add javascript text to output file or memory structure */
#if defined(__GNUC__)
__attribute__((format(printf, 1, 2)))
#endif
;
void jsOnEventBySelector(char *eventName, char *query, char *jsText);
/* Add js mapping for inline event given a query selector, e.g. '.className' */
void jsAddEventForId(char *eventName, char *idText, char *jsText);
/* Add js mapping for inline event, adding multiple events as needed */
void jsOnEventById(char *event, char *idText, char *jsText);
/* Add js mapping for inline event */
void jsOnEventByIdF(char *event, char *idText, char *format, ...)
/* Add js mapping for inline event with printf formatting */
#if defined(__GNUC__)
__attribute__((format(printf, 3, 4)))
#endif
;
void jsInlineReset();
/* used by genomeSpace to repeatedly output multiple pages to stdout */
//============ END of javascript inline-separation routines ===============
#define COLOR_BG_DEFAULT "#FFFEE8"
#define COLOR_BG_ALTDEFAULT "#FFF9D2"
#define COLOR_BG_DEFAULT_DARKER "#FCECC0"
#define COLOR_BG_DEFAULT_DARKEST "#EED5B7"
#define COLOR_BG_GHOST "#EEEEEE"
#define COLOR_BG_PALE "#F8F8F8"
#define COLOR_BG_HEADER_LTBLUE "#D9E4F8"
#define COLOR_DARKGREEN "#008800"
#define COLOR_LTGREEN "#CCFFCC"
#define COLOR_DARKBLUE "#000088"
#define COLOR_BLUE_BUTTON "#91B3E6"
#define COLOR_DARKGREY "#666666"
#define COLOR_LTGREY "#CCCCCC"
#define COLOR_YELLOW "#FFFF00"
#define COLOR_LTYELLOW "#FFF380"
#define COLOR_WHITE "#FFFFFF"
#define COLOR_RED "#AA0000"
#define COLOR_TRACKLIST_LEVEL1 COLOR_BG_DEFAULT
#define COLOR_TRACKLIST_LEVEL2 COLOR_BG_ALTDEFAULT
#define COLOR_TRACKLIST_LEVEL3 COLOR_BG_DEFAULT_DARKER
#define COLOR_TRACKLIST_LEVEL4 COLOR_BG_DEFAULT_DARKEST
void initSigHandlers(boolean dumpStack);
/* set handler for various terminal signals for logging purposes.
* if dumpStack is TRUE, attempt to dump the stack. */
struct cgiVar
/* Info on one cgi variable. */
{
struct cgiVar *next; /* Next in list. */
char *name; /* Name - allocated in hash. */
char *val; /* Value - also not allocated here. */
boolean saved; /* True if saved. */
};
struct cgiVar* cgiVarList();
/* return the list of cgiVar's */
char *cgiMemBlobRegister(char *mem, unsigned long size);
/* Record a block of memory that may be named by address in a cgi or cart
* variable, and return the "
" text that names it. The
* returned string is allocated here and belongs to the caller. */
char *cgiMemBlobFind(char *spec, unsigned long *retSize);
/* Return the block of memory named by spec, which is " " text
* made by cgiMemBlobRegister or by an uploaded file part. Return NULL if this
* program never registered such a block, in which case the address came from
* the request rather than from us and must not be used. If retSize is not
* NULL the size of the block is returned in it. */
struct cgiDictionary
/* Stuff to encapsulate parsed out CGI vars. */
{
struct cgiDictionary *next; /* Next in list if we have multiple */
char *stringData; /* Where values if cgi-vars live. */
struct hash *hash; /* Keyed by cgi-var name, value is cgiVar */
struct cgiVar *list; /* List of all vars. */
};
void cgiDictionaryFree(struct cgiDictionary **pD);
/* Free up resources associated with dictionary. */
void cgiDictionaryFreeList(struct cgiDictionary **pList);
/* Free up a whole list of cgiDictionaries */
struct cgiDictionary *cgiDictionaryFromEncodedString(char *encodedString);
/* Giving a this=that&this=that string, return cgiDictionary parsed out from it.
* This does *not* destroy input like the lower level cgiParse functions do. */
char *findCookieData(char *varName);
/* Get the string associated with varName from the cookie string. */
void dumpCookieList();
/* Print out the cookie list. */
boolean cgiIsOnWeb();
/* Return TRUE if looks like we're being run as a CGI. */
char *cgiRequestMethod();
/* Return CGI REQUEST_METHOD (such as 'GET/POST/PUT/DELETE/HEAD') */
char *cgiRequestUri();
/* Return CGI REQUEST_URI */
char *cgiRequestContentLength();
/* Return HTTP REQUEST CONTENT_LENGTH if available*/
char *cgiScriptName();
/* Return name of script so libs can do context-sensitive stuff. */
char *cgiServerName();
/* Return name of server, better to use cgiServerNamePort() for
actual URL construction */
char *cgiServerPort();
/* Return port number of server */
char *cgiServerNamePort();
/* Return name of server with port if different than 80 */
boolean cgiServerHttpsIsOn();
/* Return true if HTTPS is on */
char *cgiAppendSForHttps();
/* if running on https, add the letter s to the url protocol */
char *cgiRemoteAddr();
/* Return IP address of client (or "unknown"). */
char *cgiUserAgent();
/* Return remote user agent (HTTP_USER_AGENT) or NULL if remote user agent is not known */
enum browserType
/* How to look at a track. */
{
btUnknown=0, // Not yet known
btOpera=1, // Opera
btIE=2, // MS Internet Explorer
btFF=3, // Firefox
btChrome=4, // Google Chrome
btSafari=5, // Safari
btOther=6 // Anything else
};
enum osType
/* How to look at a track. */
{
osUnknown=0, // Not yet known
osWindows=1, // The evil empire
osLinux=2, // Workhorse
osMac=3, // ashion or Religion
osOther=4 // Anything else
};
enum browserType cgiClientBrowser(char **browserQualifier, enum osType *clientOs,
char **clientOsQualifier);
/* These routines abort the html output if the input isn't
* there or is misformatted. */
#define cgiBrowser() cgiClientBrowser(NULL,NULL,NULL)
char *cgiString(char *varName);
int cgiInt(char *varName);
double cgiDouble(char *varName);
boolean cgiBoolean(char *varName);
/* The cgiBoolean is a little problematic. If the variable
* is TRUE it exists, but if it is false it is simply not
* defined. cgiBoolean() thus returns FALSE if the CGI
* variable doesn't exist or if it is set to FALSE. To
* work around this when need be use cgiBooleanDefined(),
* which relies on the fact that when we define a boolean
* variable we also define a hidden variable. */
boolean cgiBooleanDefined(char *name);
/* Return TRUE if boolean variable is defined (by
* checking for shadow). */
char *cgiBooleanShadowPrefix();
/* Prefix for shadow variable set with boolean variables. */
void cgiMakeHiddenBoolean(char *name, boolean on);
/* Make hidden boolean variable. Also make a shadow hidden variable so we
* can distinguish between variable not present and
* variable set to false. */
char *cgiMultListShadowPrefix();
/* Prefix for shadow variable set with multi-select inputs. */
int cgiIntExp(char *varName);
/* Evaluate an integer expression in varName and
* return value. */
char *cgiOptionalString(char *varName);
/* Return value of string if it exists in cgi environment, else NULL */
char *cgiUsualString(char *varName, char *usual);
/* Return value of string if it exists in cgi environment.
* Otherwiser return 'usual' */
struct slName *cgiStringList(char *varName);
/* Find list of cgi variables with given name. This
* may be empty. Free result with slFreeList(). */
int cgiOptionalInt(char *varName, int defaultVal);
/* This returns value of varName if it exists in cgi environment,
* otherwise it returns defaultVal. */
double cgiOptionalDouble(char *varName, double defaultVal);
/* Returns double value. */
#define cgiUsualInt cgiOptionalInt
#define cgiUsualDouble cgiOptionalDouble
struct cgiChoice
/* Choice table */
{
char *name;
int value;
};
int cgiOneChoice(char *varName, struct cgiChoice *choices, int choiceSize);
/* Returns value associated with string variable in choice table. */
boolean cgiVarExists(char *varName);
/* Returns TRUE if the variable was passed in. */
void cgiBadVar(char *varName);
/* Complain about a variable that's not there. */
void cgiDecode(char *in, char *out, int inLength);
/* Decode from cgi pluses-for-spaces format to normal.
* Out will be a little shorter than in typically. */
void cgiDecodeFull(char *in, char *out, int inLength);
/* Out will be a cgi-decoded version of in (no space from plus!).
* Out will be a little shorter than in typically, and
* can be the same buffer. */
char *cgiEncode(char *inString);
/* Return a cgi-encoded version of inString.
* Alphanumerics kept as is, space translated to plus,
* and all other characters translated to %hexVal.
* You can free return value with freeMem(). */
char *cgiEncodeFull(char *inString);
/* Return a cgi-encoded version of inString (no + for space!).
* Alphanumerics/./_ kept as is and all other characters translated to
* %hexVal. */
void cgiEncodeHash(struct hash *hash, struct dyString *dy);
/* Put a cgi-encoding of a string valued hash into dy. Tags are always
* alphabetical to make it easier to compare if two hashes are same. */
void cgiMakeButtonMaybePressedMaybeSubmit(char *name, char *label, char *msg,
char *onClick, boolean pressed, boolean isSubmit);
/* Make button type input, with optional messsage and onclick javascript. Optionally this
is a submit button. Set styling to indicate whether button has been pressed (for buttons
that change browser mode).
*/
void cgiMakeSubmitButtonMaybePressed(char *name, char *value, char *msg,
char *onClick, boolean pressed);
/* Make 'submit' type button, with optional messsage and onclick javascript.
Set styling to indicate whether button has been pressed (for buttons that change browser mode).
*/
void cgiMakeNonSubmitButtonMaybePressed(char *name, char *value, char *msg,
char *onClick, boolean pressed);
/* Make button, with optional messsage and onclick javascript.
Set styling to indicate whether button has been pressed (for buttons that change browser mode).
*/
void cgiMakeButtonWithMsg(char *name, char *value, char *msg);
/* Make 'submit' type button. Display msg on mouseover, if present*/
void cgiMakeButtonWithOnClick(char *name, char *value, char *msg, char *onClick);
/* Make 'submit' type button, with onclick javascript */
void cgiMakeButton(char *name, char *value);
/* Make 'submit' type button. */
void cgiMakeOnClickButtonWithMsg(char *id, char *command, char *value, char *msg);
/* Make button (not submit) with client side onClick javascript. Display msg on mouseover. */
void cgiMakeOnClickButton(char *id, char *command, char *value);
/* Make button (not submit) with client side onClick javascript. */
void cgiMakeOnClickSubmitButton(char *command, char *name, char *value);
/* Make submit button with both variable name and value with client side
* onClick (java)script. */
void cgiMakeOptionalButton(char *name, char *value, boolean disabled);
/* Make 'submit' type button that can be disabled. */
void cgiMakeRadioButton(char *name, char *value, boolean checked);
/* Make radio type button. A group of radio buttons should have the
* same name but different values. The default selection should be
* sent with checked on. */
void cgiMakeOnEventRadioButtonWithClass(char *name, char *value, boolean checked,
char *class, char *event, char *command);
/* Make radio type button with an event and an optional class attribute.
* A group of radio buttons should have the
* same name but different values. The default selection should be
* sent with checked on. If class is non-null it is included. */
void cgiMakeCheckBoxUtil(char *name, boolean checked, char *msg, char *id);
/* Make check box - can be called directly, though it was originally meant
* as the common code for all lower level checkbox routines.
* However, it's util functionality has been taken over by
* cgiMakeCheckBoxWithIdAndOptionalHtml() */
void cgiMakeCheckBox(char *name, boolean checked);
/* Make check box. */
void cgiMakeCheckBoxWithMsg(char *name, boolean checked, char *msg);
/* Make check box, which includes a msg. */
void cgiMakeCheckBoxWithId(char *name, boolean checked, char *id);
/* Make check box, which includes an ID. */
void cgiMakeCheckBoxMore(char *name, boolean checked, char *moreHtml);
/* Make check box with moreHtml */
void cgiMakeCheckBoxEnabled(char *name, boolean checked, boolean enabled);
/* Make check box, optionally enabled/disabled. */
void cgiMakeCheckBoxIdAndMore(char *name, boolean checked, char *id, char *moreHtml);
/* Make check box with ID and extra (non-javascript) html. */
void cgiMakeCheckBoxFourWay(char *name, boolean checked, boolean enabled, char *id,
char *classes, char *moreHtml);
/* Make check box - with fourWay functionality (checked/unchecked by enabled/disabled
* Also makes a shadow hidden variable that supports the 2 boolean states. */
void cgiMakeTextArea(char *varName, char *initialVal, int rowCount, int columnCount);
/* Make a text area with area rowCount X columnCount and with text: intialVal. */
void cgiMakeTextAreaDisableable(char *varName, char *initialVal, int rowCount, int columnCount, boolean disabled);
/* Make a text area that can be disabled. The rea has rowCount X
* columnCount and with text: intialVal */
void cgiMakeTextVar(char *varName, char *initialVal, int charSize);
/* Make a text control filled with initial value. If charSize
* is zero it's calculated from initialVal size. */
void cgiMakeTextVarWithJs(char *varName, char *initialVal, int width, char *event, char *javascript);
/* Make a text control filled with initial value. */
void cgiMakeOnKeypressTextVar(char *varName, char *initialVal, int charSize,
char *script);
/* Make a text control filled with initial value, with a (java)script
* to execute every time a key is pressed. If charSize is zero it's
* calculated from initialVal size. */
void cgiMakeIntVarWithExtra(char *varName, int initialVal, int maxDigits, char *extra);
/* Make a text control filled with initial value and optional extra HTML. */
void cgiMakeIntVar(char *varName, int initialVal, int maxDigits);
/* Make a text control filled with initial integer value. */
#define NO_VALUE -96669
void cgiMakeIntVarInRange(char *varName, int initialVal, char *title, int width,
char *min, char *max);
/* Make a integer control filled with initial value.
If min and/or max are non-NULL will enforce range
Requires utils.js jQuery.js and inputBox class */
void cgiMakeIntVarWithLimits(char *varName, int initialVal, char *title, int width,
int min, int max);
void cgiMakeIntVarWithMin(char *varName, int initialVal, char *title, int width, int min);
void cgiMakeIntVarWithMax(char *varName, int initialVal, char *title, int width, int max);
#define cgiMakeIntVarNoLimits(varName,initialVal,title,width) \
cgiMakeIntVarInRange(varName,initialVal,title,width,NULL,NULL)
/* All four of these call cgiMakeIntVarInRange() and therefore require utils.js */
void cgiMakeDoubleVar(char *varName, double initialVal, int maxDigits);
/* Make a text control filled with initial floating-point value. */
void cgiMakeDoubleVarWithExtra(char *varName, double initialVal, int maxDigits, char *extra);
/* Make a text control filled with initial floating-point value and optional extra HTML. */
void cgiMakeDoubleVarInRange(char *varName, double initialVal, char *title, int width,
char *min, char *max);
/* Make a floating point control filled with initial value.
If min and/or max are non-NULL will enforce range
Requires utils.js jQuery.js and inputBox class */
void cgiMakeDoubleVarWithLimits(char *varName, double initialVal, char *title, int width,
double min, double max);
void cgiMakeDoubleVarWithMin(char *varName, double initialVal, char *title, int width, double min);
void cgiMakeDoubleVarWithMax(char *varName, double initialVal, char *title, int width, double max);
#define cgiMakeDoubleVarNoLimits(varName,initialVal,title,width) \
cgiMakeDoubleVarInRange(varName,initialVal,title,width,NULL,NULL)
/* All four of these call cgiMakeDoubleVarInRange() and therefore require utils.js */
void cgiMakeDropListClass(char *name, char *menu[], int menuSize, char *checked, char *class);
/* Make a drop-down list with names and style sheet class. */
void cgiMakeDropList(char *name, char *menu[], int menuSize, char *checked);
/* Make a drop-down list with names.
* uses style "normalText" */
void cgiMakeDropListClassWithIdStyleJavascriptAndLabel(char *name, char *id, char *menu[],
int menuSize, char *checked, char *class, char *style, struct slPair *events,
char *ariaLabel);
/* Make a drop-down list with name, id, text class, style, javascript and optional aria-label. */
void cgiMakeDropListClassWithIdStyleAndJavascript(char *name, char *id, char *menu[],
int menuSize, char *checked, char *class, char *style, struct slPair *events);
/* Make a drop-down list with name, id, text class, style and javascript. */
void cgiMakeDropListClassWithStyleAndJavascript(char *name, char *menu[],
int menuSize, char *checked, char *class,
char *style, struct slPair *events);
/* Make a drop-down list with names, text class, style and javascript. */
void cgiMakeDropListClassWithStyle(char *name, char *menu[],
int menuSize, char *checked, char *class, char *style);
/* Make a drop-down list with names, text class and style. */
void cgiMakeDropListWithVals(char *name, char *menu[], char *values[],
int menuSize, char *checked);
/* Make a drop-down list with names and values. In this case checked
* corresponds to a value, not a menu. */
void cgiMakeDropListFullExt(char *name, char *menu[], char *values[],
int menuSize, char *checked, char *event, char *javascript, char *style, char *class);
/* Make a drop-down list with names and values.
* Optionally include values for style and class */
void cgiMakeDropListFull(char *name, char *menu[], char *values[],
int menuSize, char *checked, char *event, char *javascript);
/* Make a drop-down list with names and values. */
void cgiDropDownWithTextValsAndExtra(char *name, char *text[], char *values[],
int count, char *selected, char *extra);
/* Make a drop-down list with both text and values. */
char *cgiMakeSelectDropList(boolean multiple, char *name, struct slPair *valsAndLabels,
char *selected, char *anyAll,char *extraClasses, char *event, char *javascript, char *style, char *id);
// Returns allocated string of HTML defining a drop-down select
// (if multiple, REQUIRES ui-dropdownchecklist.js)
// valsAndLabels: val (pair->name) must be filled in but label (pair->val) may be NULL.
// selected: if not NULL is a val found in the valsAndLabels (multiple then comma delimited list).
// If null and anyAll not NULL, that will be selected
// anyAll: if not NULL is the string for an initial option. It can contain val and label,
// delimited by a comma
// event: click, etc.
// javacript: what to execute when the event happens.
#define cgiMakeMultiSelectDropList(name,valsAndLabels,selected,anyAll,extraClasses,event,javascript,style,id) \
cgiMakeSelectDropList(TRUE,(name),(valsAndLabels),(selected),(anyAll),\
(extraClasses),(event),(javascript),(style),(id))
#define cgiMakeSingleSelectDropList(name,valsAndLabels,selected,anyAll,extraClasses,event,javascript,style,id) \
cgiMakeSelectDropList(FALSE,(name),(valsAndLabels),(selected),(anyAll),\
(extraClasses),(event),(javascript),(style),(id))
void cgiMakeMultList(char *name, char *menu[], int menuSize, struct slName *checked, int length);
/* Make a list of names which can have multiple selections.
* Same as drop-down list except "multiple" is added to select tag */
void cgiMakeCheckboxGroup(char *name, char *menu[], int menuSize, struct slName *checked,
int tableColumns);
/* Make a table of checkboxes that have the same variable name but different
* values (same behavior as a multi-select input). */
void cgiMakeCheckboxGroupWithVals(char *name, char *menu[], char *values[], int menuSize,
struct slName *checked, int tableColumns);
/* Make a table of checkboxes that have the same variable name but different
* values (same behavior as a multi-select input), with nice labels in menu[]. */
void cgiMakeHiddenVarWithIdExtra(char *varName, char *id, char *string,char *extra);
/* Store string in hidden input for next time around. */
#define cgiMakeHiddenVarWithExtra(name,val,extra) cgiMakeHiddenVarWithIdExtra((name),NULL,(val),extra)
/* Store string in hidden input for next time around. */
#define cgiMakeHiddenVar(name,val) cgiMakeHiddenVarWithExtra((name),(val),NULL)
/* Store string in hidden input for next time around. */
void cgiContinueHiddenVar(char *varName);
/* Write CGI var back to hidden input for next time around.
* (if it exists). */
void cgiContinueAllVars();
/* Write back all CGI vars as hidden input for next time around. */
void cgiVarExclude(char *varName);
/* If varName exists, remove it. */
void cgiVarExcludeExcept(char **varNames);
/* Exclude all variables except for those in NULL
* terminated array varNames. varNames may be NULL
* in which case nothing is excluded. */
void cgiVarSet(char *varName, char *val);
/* Set a cgi variable to a particular value. */
struct dyString *cgiUrlString();
/* Get URL-formatted that expresses current CGI variable state. */
void cgiEncodeIntoDy(char *var, char *val, struct dyString *dy);
/* Add a CGI-encoded &var=val string to dy. */
boolean cgiSpoof(int *pArgc, char *argv[]);
/* Use the command line to set up things as if we were a CGI program.
* User types in command line (assuming your program called cgiScript)
* like:
* cgiScript nonCgiArg1 var1=value1 var2=value2 var3=value3 nonCgiArg2
* or like
* cgiScript nonCgiArg1 var1=value1&var2=value2&var3=value3 nonCgiArg2
* (The non-cgi arguments can occur anywhere. The cgi arguments (all containing
* the character '=') are erased from argc/argv. Normally you call this
* cgiSpoof(&argc, argv);
*/
boolean cgiWasSpoofed();
/* was the CGI run from the command line? */
boolean cgiFromCommandLine(int *pArgc, char *argv[], boolean preferWeb);
/* Use the command line to set up things as if we were a CGI program.
* If preferWeb is TRUE will choose real CGI variables over command
* line ones. */
void useTempFile();
/* tell cheapcgi to use temp files */
boolean cgiFromFile(char *fileName);
/* Set up a cgi environment using parameters stored in a file.
* Takes file with arguments in the form:
* argument1=someVal
* # This is a comment
* argument2=someOtherVal
* ...
* and puts them into the cgi environment so that the usual
* cgiGetVar() commands can be used. Useful when a program
* has a lot of possible parameters.
*/
boolean cgiParseInput(char *input, struct hash **retHash,
struct cgiVar **retList);
/* Parse cgi-style input into a hash table and list. This will alter
* the input data. The hash table will contain references back
* into input, so please don't free input until you're done with
* the hash. Prints message and returns FALSE if there's an error.
* To clean up - slFreeList, hashFree, and only then free input. */
void cgiParseInputAbort(char *input, struct hash **retHash,
struct cgiVar **retList);
/* Parse cgi-style input into a hash table and list as above but abort if there's an error. */
char *cgiStringNewValForVar(char *cgiIn, char *varName, char *newVal);
/* Return a cgi-encoded string with newVal in place of what was oldVal.
* It is an error for var not to exist. Do a freeMem of this string
* when you are through. */
void cgiSimpleTableStart();
/* start HTML table -- no customization. Leaves room
* for a fancier implementation */
void cgiTableEnd();
/* end HTML table */
void cgiMakeSubmitButton();
/* Make 'submit' type button. */
void cgiMakeResetButton();
/* Make 'reset' type button. */
void cgiMakeCancelButton(char *label);
/* Make button named 'Cancel' (for modal dialogs), with optional label (e.g. OK) */
void cgiMakeClearButton(char *form, char *field);
/* Make button to clear a text field. */
void cgiMakeClearButtonNoSubmit(char *form, char *field);
/* Make button to clear a text field, without resubmitting the form. */
void cgiMakeFileEntry(char *name);
/* Make file entry box/browser */
void cgiSimpleTableRowStart();
/* Start table row */
void cgiTableRowEnd();
/* End table row */
void cgiSimpleTableFieldStart();
/* Start table field */
void cgiTableFieldStartAlignRight();
/* Start table field */
void cgiTableFieldEnd();
/* End table field */
void cgiTableField(char *text);
/* Make table field entry */
void cgiTableFieldWithMsg(char *text, char *msg);
/* Make table field entry with mouseover */
void cgiParagraph(char *text);
/* Make text paragraph */
void logCgiToStderr();
/* Log useful CGI info to stderr */
void cgiResetState();
/* This is for reloading CGI settings multiple times in the same program
* execution. No effect if state has not yet been initialized. */
void cgiDown(float lines);
// Drop down a certain number of lines (may be fractional)
char *commonCssStyles();
/* Returns a string of common CSS styles */
char *javaScriptLiteralEncode(char *inString);
/* Use backslash escaping on newline
* and quote chars, backslash and others.
* Intended that the encoded string will be
* put between quotes at a higher level and
* then interpreted by Javascript. */
boolean cgiParseNext(char **pInput, char **retVar, char **retVal);
/* Parse out next var/val in a var=val&var=val... cgi formatted string
* This will insert zeroes and other things into string.
* Usage:
* char *pt = cgiStringStart;
* char *var, *val
* while (cgiParseNext(&pt, &var, &val))
* printf("%s\t%s\n", var, val); */
struct cgiParsedVars
/* A parsed out cgi variable string */
{
struct cgiParsedVars *next; /* In case want to make a list of these. */
char *stringBuf; /* Holds strings inside vars. */
struct cgiVar *list; /* List of variables. */
struct hash *hash; /* Keyed by varName, value is just value, not cgiVar. */
};
struct cgiParsedVars *cgiParsedVarsNew(char *cgiString);
/* Build structure containing parsed out cgiString */
void cgiParsedVarsFree(struct cgiParsedVars **pTags);
/* Free up memory associated with cgiParsedVars */
void cgiParsedVarsFreeList(struct cgiParsedVars **pList);
/* Free up list of cgiParsedVars */
char *cgiScriptDirUrl();
/* Return the cgi-bin directory path on this webserver.
* This is not the local directory but the part after the server
* in external URLs to this webserver.
* e.g. if CGI is called via http://localhost/subdir/cgi-bin/cgiTest
* the returned string is /subdir/. Must be free'd. */
void cgiChangeVar(char *varName, char *value);
/* An entry point to change the value of a something passed to us on the URL. */
void cgiSetMaxLogLen(int l);
/* set the size of variable values that are dumped to stderr. Default is 0, which means no logging */
boolean isValidJsonpCallback(char *s);
/* Return TRUE if s is safe to use as a JSONP callback name: non-empty, not
* too long, and every dot-separated segment is a C symbol (letters, digits,
* underscore, not starting with a digit). This rejects anything with
* parentheses, spaces, operators, or other characters that would let an
* attacker turn a same-origin JSONP response into arbitrary script. */
#endif /* CHEAPCGI_H */