From a0617c1edb825da01d3a249c24df2cc56931fe1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Ca=C3=B1as=20Vargas?= Date: Wed, 30 Mar 2016 14:25:04 +0200 Subject: [PATCH] Version 15.168 --- swad_changelog.h | 3 +- swad_global.c | 7 +- swad_global.h | 22 ++++-- swad_layout.c | 2 +- swad_parameter.c | 173 +++++++++++++++++++++++++++++++++++------------ swad_parameter.h | 12 ++++ 6 files changed, 164 insertions(+), 55 deletions(-) diff --git a/swad_changelog.h b/swad_changelog.h index 2d9eb3ce..9bd5a344 100644 --- a/swad_changelog.h +++ b/swad_changelog.h @@ -138,13 +138,14 @@ /****************************** Public constants *****************************/ /*****************************************************************************/ -#define Log_PLATFORM_VERSION "SWAD 15.167 (2016-03-29)" +#define Log_PLATFORM_VERSION "SWAD 15.168 (2016-03-29)" #define CSS_FILE "swad15.165.5.css" #define JS_FILE "swad15.131.3.js" // Number of lines (includes comments but not blank lines) has been got with the following command: // nl swad*.c swad*.h css/swad*.css py/swad*.py js/swad*.js soap/swad*.h sql/swad*.sql | tail -1 /* + Version 15.168: Mar 30, 2016 When content is normal, all parameters are retrieved in a list. (197085 lines) Version 15.167: Mar 30, 2016 Query string is allocated to the exact needed size to optimize memory. (196998 lines) Version 15.166.1: Mar 30, 2016 Fixed bug while reading a parameter. (196959 lines) Version 15.166: Mar 30, 2016 Changes in form to edit a test question. diff --git a/swad_global.c b/swad_global.c index eabd2988..ac44a73d 100644 --- a/swad_global.c +++ b/swad_global.c @@ -105,8 +105,10 @@ void Gbl_InitializeGlobals (void) Gbl.WebService.IsWebService = false; - Gbl.ContentLength = 0; - Gbl.QueryString = NULL; + Gbl.Params.ContentLength = 0; + Gbl.Params.QueryString = NULL; + Gbl.Params.List = NULL; + Gbl.Params.GetMethod = false; Gbl.F.Out = stdout; Gbl.F.Tmp = NULL; @@ -117,7 +119,6 @@ void Gbl_InitializeGlobals (void) Gbl.Error = false; - Gbl.GetMethod = false; Gbl.Layout.WritingHTMLStart = Gbl.Layout.HTMLStartWritten = diff --git a/swad_global.h b/swad_global.h index 628325ad..042e9ba6 100644 --- a/swad_global.h +++ b/swad_global.h @@ -95,13 +95,23 @@ struct Globals bool Inside; // Set to true inside a form to avoid nested forms } Form; bool Error; - bool GetMethod; // Am I accessed using GET method? - struct soap *soap; // gSOAP runtime environment + + struct + { + size_t ContentLength; + char *QueryString; // String allocated dynamically with the arguments sent to the CGI + struct Param *List; // Linked list of parameters + bool GetMethod; // Am I accessing using GET method? + } Params; + Act_Content_t ContentReceivedByCGI; /* Content send by the form and received by the CGI: - Act_CONTENT_NORM (if CONTENT_TYPE==text/plain) or - Act_CONTENT_DATA (if CONTENT_TYPE==multipart/form-data) */ + Act_CONTENT_NORM (if CONTENT_TYPE==text/plain) or + Act_CONTENT_DATA (if CONTENT_TYPE==multipart/form-data) */ char DelimiterString[1000]; char DelimiterStringIncludingInitialRet[2+1000]; + + struct soap *soap; // gSOAP runtime environment + struct { bool WritingHTMLStart; // Used to avoid writing the HTML head when aborting program on error @@ -115,7 +125,7 @@ struct Globals bool LockedTables; } DB; - bool HiddenParamsInsertedIntoDB; // Indica si se ha insertado algún parameter in the database in esta ejecución + bool HiddenParamsInsertedIntoDB; // If parameters are inserted in the database in this execution /* To compute execution time of the program */ struct timeval tvStart,tvPageCreated,tvPageSent; @@ -702,8 +712,6 @@ struct Globals float MaxPercent; } DegPhotos; } Stat; - size_t ContentLength; - char *QueryString; // String allocated dynamically with the arguments sent to the CGI }; /*****************************************************************************/ diff --git a/swad_layout.c b/swad_layout.c index 29a26a4e..556e01e3 100644 --- a/swad_layout.c +++ b/swad_layout.c @@ -369,7 +369,7 @@ static void Lay_WritePageTitle (void) fprintf (Gbl.F.Out,""); - if (Gbl.GetMethod && Gbl.CurrentDeg.Deg.DegCod > 0) + if (Gbl.Params.GetMethod && Gbl.CurrentDeg.Deg.DegCod > 0) { fprintf (Gbl.F.Out,"%s > %s", Cfg_PLATFORM_SHORT_NAME, diff --git a/swad_parameter.c b/swad_parameter.c index 9a6807b0..af5b0ef7 100644 --- a/swad_parameter.c +++ b/swad_parameter.c @@ -59,6 +59,8 @@ extern struct Globals Gbl; /***************************** Private prototypes ****************************/ /*****************************************************************************/ +static void Par_GetParameters (void); + static void Par_ShowErrorReadingParam (const char *ParamName,const char *ExpectedChar,int Ch); /*****************************************************************************/ @@ -76,18 +78,18 @@ bool Par_GetQueryString (void) if (!strcmp (Method,"GET")) { /***** GET method *****/ - Gbl.GetMethod = true; + Gbl.Params.GetMethod = true; Gbl.ContentReceivedByCGI = Act_CONTENT_NORM; /* Get content length */ - Gbl.ContentLength = strlen (getenv ("QUERY_STRING")); + Gbl.Params.ContentLength = strlen (getenv ("QUERY_STRING")); /* Allocate memory for query string */ - if ((Gbl.QueryString = (char *) malloc (Gbl.ContentLength + 1)) == NULL) + if ((Gbl.Params.QueryString = (char *) malloc (Gbl.Params.ContentLength + 1)) == NULL) return false; /* Copy query string from environment variable */ - strcpy (Gbl.QueryString,getenv ("QUERY_STRING")); + strcpy (Gbl.Params.QueryString,getenv ("QUERY_STRING")); } else { @@ -96,7 +98,7 @@ bool Par_GetQueryString (void) if (getenv ("CONTENT_LENGTH")) { strcpy (UnsignedLongStr,getenv ("CONTENT_LENGTH")); - if (sscanf (UnsignedLongStr,"%lu",&Gbl.ContentLength) != 1) + if (sscanf (UnsignedLongStr,"%lu",&Gbl.Params.ContentLength) != 1) return false; } else @@ -132,18 +134,22 @@ bool Par_GetQueryString (void) Gbl.ContentReceivedByCGI = Act_CONTENT_NORM; /* Allocate memory for query string */ - if ((Gbl.QueryString = (char *) malloc (Gbl.ContentLength + 1)) == NULL) + if ((Gbl.Params.QueryString = (char *) malloc (Gbl.Params.ContentLength + 1)) == NULL) return false; /* Copy query string from stdin */ - if (fread ((void *) Gbl.QueryString,sizeof (char),Gbl.ContentLength,stdin) != Gbl.ContentLength) + if (fread ((void *) Gbl.Params.QueryString,sizeof (char),Gbl.Params.ContentLength,stdin) != Gbl.Params.ContentLength) { - Gbl.QueryString[0] = '\0'; + Gbl.Params.QueryString[0] = '\0'; return false; } - Gbl.QueryString[Gbl.ContentLength] = '\0'; + Gbl.Params.QueryString[Gbl.Params.ContentLength] = '\0'; } } + + if (Gbl.ContentReceivedByCGI == Act_CONTENT_NORM) + Par_GetParameters (); + return true; } @@ -153,8 +159,8 @@ bool Par_GetQueryString (void) void Par_FreeQueryString (void) { - if (Gbl.QueryString) - free ((void *) Gbl.QueryString); + if (Gbl.Params.QueryString) + free ((void *) Gbl.Params.QueryString); } /*****************************************************************************/ @@ -447,6 +453,95 @@ unsigned Par_GetParAndChangeFormat (const char *ParamName,char *ParamValue,size_ return NumTimes; } + +/*****************************************************************************/ +/************************* Get the value of a parameter **********************/ +/*****************************************************************************/ +// Return the number of parameters found + +#define Par_LENGTH_OF_STR_BEFORE_PARAM 38 // Length of "CONTENT-DISPOSITION: FORM-DATA; NAME=\"" +#define Par_MAX_BYTES_STR_AUX 1024 + +static void Par_GetParameters (void) + { + unsigned long i; + struct Param *Param; + struct Param *NewParam; + + switch (Gbl.ContentReceivedByCGI) + { + case Act_CONTENT_NORM: + if (Gbl.Params.QueryString == NULL) + { + Gbl.Params.List = NULL; + return; + } + if (!Gbl.Params.QueryString[0]) + { + Gbl.Params.List = NULL; + return; + } + + for (i = 0; + i < Gbl.Params.ContentLength; + ) + { + /* Allocate space for parameter */ + if ((NewParam = (struct Param *) malloc (sizeof (struct Param))) == NULL) + Lay_ShowErrorAndExit ("Error allocating memory for parameter"); + + /* Point last element in list to this */ + if (i == 0) + Gbl.Params.List = NewParam; + else + Param->Next = NewParam; + + /* Point current element to the new just created */ + Param = NewParam; + Param->Next = NULL; + + /* Get parameter name */ + Param->Name.Start = i; + Param->Name.Length = strcspn (&Gbl.Params.QueryString[i],"="); + + /* Get parameter value */ + i += Param->Name.Length; + if (i < Gbl.Params.ContentLength) + { + if (Gbl.Params.QueryString[i] == '=') + { + i++; // Skip '=' + Param->Value.Start = i; + if (i < Gbl.Params.ContentLength) + { + Param->Value.Length = strcspn (&Gbl.Params.QueryString[i],"&"); + i += Param->Value.Length; + if (i < Gbl.Params.ContentLength) + if (Gbl.Params.QueryString[i] == '&') + i++; // Skip '&' + } + else + Param->Value.Length = 0; + } + else + { + Param->Value.Start = i; + Param->Value.Length = 0; + } + } + else + { + Param->Value.Start = i; + Param->Value.Length = 0; + } + } + break; + case Act_CONTENT_DATA: + // TODO: Implement + break; + } + } + /*****************************************************************************/ /************************* Get the value of a parameter **********************/ /*****************************************************************************/ @@ -463,9 +558,9 @@ unsigned Par_GetParameter (tParamType ParamType,const char *ParamName, size_t BytesAlreadyCopied = 0; int Ch; unsigned i; - char *PtrSrc; + struct Param *Param; char *PtrDst; - char *PtrStartOfParam; + const char *PtrSrc = NULL; int Result; unsigned NumTimes = 0; bool ParamFound = false; @@ -479,7 +574,7 @@ unsigned Par_GetParameter (tParamType ParamType,const char *ParamName, switch (Gbl.ContentReceivedByCGI) { case Act_CONTENT_NORM: - if (Gbl.GetMethod) // Only some selected parameters can be passed by GET method + if (Gbl.Params.GetMethod) // Only some selected parameters can be passed by GET method { if (strcmp (ParamName,"cty") && // To enter directly to a country strcmp (ParamName,"ins") && // To enter directly to an institution @@ -493,38 +588,28 @@ unsigned Par_GetParameter (tParamType ParamType,const char *ParamName, strcmp (ParamName,"key")) // To verify an email address return 0; // Return no-parameters-found when method is GET and parameter name is not one of these } - PtrSrc = Gbl.QueryString; + PtrDst = ParamValue; + Param = Gbl.Params.List; for (NumTimes = 0; NumTimes < 1 || ParamType == Par_PARAM_MULTIPLE; NumTimes++) { - ParamFound = false; - do - { - /* If method is GET ==> do case insensitive comparison */ - PtrStartOfParam = strstr (PtrSrc,ParamName); - if (PtrStartOfParam) - { - // String ParamName found inside Gbl.QueryString - if (*(PtrStartOfParam + ParamNameLength) == '=') + for (ParamFound = false; + Param != NULL && !ParamFound; + Param = Param->Next) + if (ParamNameLength == Param->Name.Length) + if (!strncmp (ParamName,&Gbl.Params.QueryString[Param->Name.Start], + Param->Name.Length)) { - // Just after the name of the parameter, must be found a '=' symbol - if (PtrStartOfParam == Gbl.QueryString) // The parameter is just at start - ParamFound = true; - else if (*(PtrStartOfParam - 1) == '&') // The parameter is not at start, but just after an "&" separator - ParamFound = true; - else // String has been found at the end of another parameter - PtrSrc = PtrStartOfParam + ParamNameLength; + ParamFound = true; + if ((BytesToCopy = Param->Value.Length)) + PtrSrc = &Gbl.Params.QueryString[Param->Value.Start]; } - else // String has been found, but it is not a parameter - PtrSrc = PtrStartOfParam + ParamNameLength; - } - } - while (PtrStartOfParam != NULL && !ParamFound); - if (!ParamFound) // Not found ==> PtrStartOfParam == NULL + + if (!ParamFound) break; - PtrSrc = PtrStartOfParam + ParamNameLength + 1; // Add 1 due to the '=' symbol + if (NumTimes) { if (BytesAlreadyCopied + 1 > MaxBytes) @@ -537,7 +622,7 @@ unsigned Par_GetParameter (tParamType ParamType,const char *ParamName, *PtrDst++ = Par_SEPARATOR_PARAM_MULTIPLE; // Separator in the destination string BytesAlreadyCopied++; } - BytesToCopy = strcspn (PtrSrc,"&"); // The & charecter is the separator of two parameters + if (BytesAlreadyCopied + BytesToCopy > MaxBytes) { sprintf (Gbl.Message,"Parameter <strong>%s</strong> too large," @@ -545,10 +630,12 @@ unsigned Par_GetParameter (tParamType ParamType,const char *ParamName, ParamName,(unsigned long) MaxBytes); Lay_ShowErrorAndExit (Gbl.Message); } - strncpy (PtrDst,PtrSrc,BytesToCopy); - BytesAlreadyCopied += BytesToCopy; - PtrDst += BytesToCopy; - PtrSrc += BytesToCopy; + if (BytesToCopy) + { + strncpy (PtrDst,PtrSrc,BytesToCopy); + BytesAlreadyCopied += BytesToCopy; + PtrDst += BytesToCopy; + } } *PtrDst = '\0'; // strncpy() does not add the final NULL break; diff --git a/swad_parameter.h b/swad_parameter.h index 354363e2..2969b19a 100644 --- a/swad_parameter.h +++ b/swad_parameter.h @@ -34,6 +34,18 @@ /************************** Public types and constants ***********************/ /*****************************************************************************/ +struct StartLength + { + unsigned long Start; + size_t Length; + }; +struct Param + { + struct StartLength Name; + struct StartLength Value; + struct Param *Next; + }; + typedef enum { Par_PARAM_SINGLE,