diff --git a/swad_changelog.h b/swad_changelog.h index f59530ed..2d9eb3ce 100644 --- a/swad_changelog.h +++ b/swad_changelog.h @@ -131,17 +131,22 @@ // TODO: Do not show e-mails of administrators and teachers in lists openly // TODO: Fix bug in marks reported by Francisco Ocaņa +// TODO: Optimize reading of parameters by doing one unique pass creating a dynamic list of parameters and their values +// This is very important when there is a big file in the middle of the list of parameters + /*****************************************************************************/ /****************************** Public constants *****************************/ /*****************************************************************************/ -#define Log_PLATFORM_VERSION "SWAD 15.166 (2016-03-29)" +#define Log_PLATFORM_VERSION "SWAD 15.167 (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.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. Fixed bug while reading a parameter. (196943 lines) Version 15.165.8: Mar 30, 2016 Changes related to image in test questions. (196896 lines) diff --git a/swad_constant.h b/swad_constant.h index 5a1338f4..18c091ad 100644 --- a/swad_constant.h +++ b/swad_constant.h @@ -33,8 +33,6 @@ /***************************** Public constants ******************************/ /*****************************************************************************/ -#define Cns_MAX_LENGTH_ARGS_SENT_TO_CGI (1024UL*1024UL-1) // Very big space for arguments - #define Cns_MAX_LENGTH_WWW 255 // Max. length of a URL #define Cns_MAX_LENGTH_IP 15 // Max. bytes of an IP address diff --git a/swad_file.c b/swad_file.c index 8095265d..63285f8f 100644 --- a/swad_file.c +++ b/swad_file.c @@ -163,7 +163,7 @@ bool Fil_ReadStdinIntoTmpFile (void) } rewind (Gbl.F.Tmp); -/* For debug +/* FILE *FileTgt; ***** Open destination file ***** diff --git a/swad_global.c b/swad_global.c index 188bd192..eabd2988 100644 --- a/swad_global.c +++ b/swad_global.c @@ -41,6 +41,7 @@ #include "swad_exam.h" #include "swad_global.h" #include "swad_icon.h" +#include "swad_parameter.h" #include "swad_preference.h" #include "swad_theme.h" #include "swad_web_service.h" @@ -104,6 +105,9 @@ void Gbl_InitializeGlobals (void) Gbl.WebService.IsWebService = false; + Gbl.ContentLength = 0; + Gbl.QueryString = NULL; + Gbl.F.Out = stdout; Gbl.F.Tmp = NULL; Gbl.F.XML = NULL; @@ -468,4 +472,5 @@ void Gbl_Cleanup (void) if (Gbl.F.Tmp) fclose (Gbl.F.Tmp); Fil_CloseXMLFile (); + Par_FreeQueryString (); } diff --git a/swad_global.h b/swad_global.h index 0da993d7..628325ad 100644 --- a/swad_global.h +++ b/swad_global.h @@ -702,7 +702,8 @@ struct Globals float MaxPercent; } DegPhotos; } Stat; - char QueryString[Cns_MAX_LENGTH_ARGS_SENT_TO_CGI+1]; // String with the arguments sent to the CGI + size_t ContentLength; + char *QueryString; // String allocated dynamically with the arguments sent to the CGI }; /*****************************************************************************/ diff --git a/swad_parameter.c b/swad_parameter.c index 5a783e8c..9a6807b0 100644 --- a/swad_parameter.c +++ b/swad_parameter.c @@ -69,17 +69,39 @@ bool Par_GetQueryString (void) { char Method[256]; char ContentType[512]; + char UnsignedLongStr[10+1]; strcpy (Method,getenv ("REQUEST_METHOD")); if (!strcmp (Method,"GET")) { + /***** GET method *****/ Gbl.GetMethod = true; Gbl.ContentReceivedByCGI = Act_CONTENT_NORM; + + /* Get content length */ + Gbl.ContentLength = strlen (getenv ("QUERY_STRING")); + + /* Allocate memory for query string */ + if ((Gbl.QueryString = (char *) malloc (Gbl.ContentLength + 1)) == NULL) + return false; + + /* Copy query string from environment variable */ strcpy (Gbl.QueryString,getenv ("QUERY_STRING")); } else { + /***** PUSH method *****/ + /* Get content length */ + if (getenv ("CONTENT_LENGTH")) + { + strcpy (UnsignedLongStr,getenv ("CONTENT_LENGTH")); + if (sscanf (UnsignedLongStr,"%lu",&Gbl.ContentLength) != 1) + return false; + } + else + return false; + /* If data are received ==> the environment variable CONTENT_TYPE will hold: multipart/form-data; boundary=---------------------------7d13ca2e948 */ @@ -109,14 +131,32 @@ bool Par_GetQueryString (void) { Gbl.ContentReceivedByCGI = Act_CONTENT_NORM; - /***** Get the string sent by form *****/ - if (fgets (Gbl.QueryString,Cns_MAX_LENGTH_ARGS_SENT_TO_CGI,stdin) == NULL) + /* Allocate memory for query string */ + if ((Gbl.QueryString = (char *) malloc (Gbl.ContentLength + 1)) == NULL) + return false; + + /* Copy query string from stdin */ + if (fread ((void *) Gbl.QueryString,sizeof (char),Gbl.ContentLength,stdin) != Gbl.ContentLength) + { Gbl.QueryString[0] = '\0'; + return false; + } + Gbl.QueryString[Gbl.ContentLength] = '\0'; } } return true; } +/*****************************************************************************/ +/***************** Free memory allocated for query string ********************/ +/*****************************************************************************/ + +void Par_FreeQueryString (void) + { + if (Gbl.QueryString) + free ((void *) Gbl.QueryString); + } + /*****************************************************************************/ /****************** Get the parameters sent to this CGI **********************/ /*****************************************************************************/ @@ -418,7 +458,7 @@ unsigned Par_GetParAndChangeFormat (const char *ParamName,char *ParamValue,size_ unsigned Par_GetParameter (tParamType ParamType,const char *ParamName, char *ParamValue,size_t MaxBytes) { - static const char *StringBeforeParam = "CONTENT-DISPOSITION: FORM-DATA; NAME=\""; + static const char *StringBeforeParam = "Content-Disposition: form-data; name=\""; size_t BytesToCopy; size_t BytesAlreadyCopied = 0; int Ch; @@ -472,9 +512,9 @@ unsigned Par_GetParameter (tParamType ParamType,const char *ParamName, // 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 + 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 + else // String has been found at the end of another parameter PtrSrc = PtrStartOfParam + ParamNameLength; } else // String has been found, but it is not a parameter @@ -517,7 +557,10 @@ unsigned Par_GetParameter (tParamType ParamType,const char *ParamName, while (ContinueSearching) { - Result = Str_ReceiveFileUntilDelimitStr (Gbl.F.Tmp,NULL,StrAux,Gbl.DelimiterString,(unsigned long long) Par_MAX_BYTES_STR_AUX); + Result = Str_ReceiveFileUntilDelimitStr (Gbl.F.Tmp, + (FILE *) NULL,(char *) NULL, + Gbl.DelimiterString, + Fil_MAX_FILE_SIZE); switch (Result) { case -1: // Delimiter string not found @@ -531,9 +574,15 @@ unsigned Par_GetParameter (tParamType ParamType,const char *ParamName, do Ch = fgetc (Gbl.F.Tmp); while (isspace (Ch) && Ch != EOF); + if (Ch == (int) StringBeforeParam[0]) - if (!strcasecmp (Str_GetNextStrFromFileConvertingToLower (Gbl.F.Tmp,StrAux,Par_LENGTH_OF_STR_BEFORE_PARAM-1),StringBeforeParam+1)) // Start of a parameter - if (!strcasecmp (Str_GetNextStrFromFileConvertingToLower (Gbl.F.Tmp,StrAux,ParamNameLength),ParamName)) // Parameter found + { + Str_GetNextStrFromFileConvertingToLower (Gbl.F.Tmp,StrAux,Par_LENGTH_OF_STR_BEFORE_PARAM-1); + if (!strcasecmp (StrAux,StringBeforeParam+1)) // Start of a parameter + { + /* Check if parameter is the parameter that we are looking for */ + Str_GetNextStrFromFileConvertingToLower (Gbl.F.Tmp,StrAux,ParamNameLength); + if (!strcasecmp (StrAux,ParamName)) // Parameter found { /* Skip quote after parameter name */ Ch = fgetc (Gbl.F.Tmp); @@ -554,7 +603,10 @@ unsigned Par_GetParameter (tParamType ParamType,const char *ParamName, } /* Get the parameter */ - Result = Str_ReceiveFileUntilDelimitStr (Gbl.F.Tmp,(FILE *) NULL,ParamValue,Gbl.DelimiterStringIncludingInitialRet,(unsigned long long) MaxBytes); + Result = Str_ReceiveFileUntilDelimitStr (Gbl.F.Tmp, + (FILE *) NULL,ParamValue, + Gbl.DelimiterStringIncludingInitialRet, + (unsigned long long) MaxBytes); /* Depending on the result... */ switch (Result) @@ -576,6 +628,8 @@ unsigned Par_GetParameter (tParamType ParamType,const char *ParamName, break; } } + } + } break; } } diff --git a/swad_parameter.h b/swad_parameter.h index 91dfd04e..354363e2 100644 --- a/swad_parameter.h +++ b/swad_parameter.h @@ -47,6 +47,7 @@ typedef enum /*****************************************************************************/ bool Par_GetQueryString (void); +void Par_FreeQueryString (void); void Par_GetMainParameters (void); unsigned Par_GetParToText (const char *ParamName,char *ParamValue,size_t MaxBytes);