From 04f30ff80031771cf88cf2bf608618136b0ce1e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Ca=C3=B1as=20Vargas?= Date: Thu, 31 Mar 2016 02:15:17 +0200 Subject: [PATCH] Version 15.169 --- swad_changelog.h | 3 +- swad_parameter.c | 228 +++++++++++++++++++++++++++++++++++++++-------- swad_parameter.h | 6 +- swad_string.c | 49 ++++++++++ swad_string.h | 3 +- 5 files changed, 250 insertions(+), 39 deletions(-) diff --git a/swad_changelog.h b/swad_changelog.h index 05bd52f9..a6880369 100644 --- a/swad_changelog.h +++ b/swad_changelog.h @@ -138,13 +138,14 @@ /****************************** Public constants *****************************/ /*****************************************************************************/ -#define Log_PLATFORM_VERSION "SWAD 15.168.3 (2016-03-30)" +#define Log_PLATFORM_VERSION "SWAD 15.169 (2016-03-31)" #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.169: Mar 31, 2016 When content is data, all parameters are retrieved in a list. (197306 lines) Version 15.168.3: Mar 30, 2016 Code refactoring in list of parameters. (197124 lines) Version 15.168.2: Mar 30, 2016 Code refactoring in list of parameters. (197128 lines) Version 15.168.1: Mar 30, 2016 Fixed bug in list of parameters. (197097 lines) diff --git a/swad_parameter.c b/swad_parameter.c index e3abce58..d2796e76 100644 --- a/swad_parameter.c +++ b/swad_parameter.c @@ -62,6 +62,8 @@ extern struct Globals Gbl; static void Par_CreateListOfParams (void); static void Par_CreateListOfParamsFromQueryString (void); static void Par_CreateListOfParamsFromTmpFile (void); +static int Par_ReadTmpFileUntilQuote (void); +static int Par_ReadTmpFileUntilReturn (void); static void Par_ShowErrorReadingParam (const char *ParamName,const char *ExpectedChar,int Ch); @@ -157,18 +159,27 @@ bool Par_GetQueryString (void) /*****************************************************************************/ /************************ Create list of parameters **************************/ /*****************************************************************************/ -/* Parameter #1 Parameter #2 Parameter #3 - +-------------+ +-------------+ +-------------+ -List -> | Name.Start | --> | Name.Start | --> | Name.Start | - +-------------+ / +-------------+ / +-------------+ - | Name.Length | / | Name.Length | / | Name.Length | - +-------------+ / +-------------+ / +-------------+ - | Value.Start | / | Value.Start | / | Value.Start | - +-------------+ / +-------------+ / +-------------+ - | Value.Lengh | / | Value.Lengh | / | Value.Lengh | - +-------------+ / +-------------+ / +-------------+ - | Next ----- | Next ----- | NULL | - +-------------+ +-------------+ +-------------+ +/* + Parameter #1 Parameter #n + +------------------+ +------------------+ +List --> |Name.Start | -> |Name.Start | + +------------------+ / +------------------+ + |Name.Length | | |Name.Length | + +------------------+ | +------------------+ + |Filename.Start | | |Filename.Start | + +------------------+ | +------------------+ + |Filename.Lenght | | |Filename.Lenght | + +------------------+ . +------------------+ + |ContentType.Start | . |ContentType.Start | + +------------------+ . +------------------+ + |ContentType.Lenght| | |ContentType.Lenght| + +------------------+ | +------------------+ + |Value.Start | | |Value.Start | + +------------------+ | +------------------+ + |Value.Lengh | | |Value.Lengh | + +------------------+ / +------------------+ + | Next -------- | NULL | + +------------------+ +------------------+ */ static void Par_CreateListOfParams (void) @@ -196,6 +207,8 @@ static void Par_CreateListOfParamsFromQueryString (void) /***** Check if query string is empty *****/ Gbl.Params.List = NULL; + if (!Gbl.Params.ContentLength) + return; if (Gbl.Params.QueryString == NULL) return; if (!Gbl.Params.QueryString[0]) @@ -207,8 +220,8 @@ static void Par_CreateListOfParamsFromQueryString (void) CurPos < Gbl.Params.ContentLength; ) { - /* Allocate space for a new parameter */ - if ((NewParam = (struct Param *) malloc (sizeof (struct Param))) == NULL) + /* Allocate space for a new parameter initialized to 0 */ + if ((NewParam = (struct Param *) calloc (1,sizeof (struct Param))) == NULL) Lay_ShowErrorAndExit ("Error allocating memory for parameter"); /* Link the previous element in list with the current element */ @@ -219,7 +232,6 @@ static void Par_CreateListOfParamsFromQueryString (void) /* Make the current element to be the just created */ Param = NewParam; - Param->Next = NULL; /* Get parameter name */ Param->Name.Start = CurPos; @@ -228,33 +240,19 @@ static void Par_CreateListOfParamsFromQueryString (void) /* Get parameter value */ if (CurPos < Gbl.Params.ContentLength) - { if (Gbl.Params.QueryString[CurPos] == '=') { CurPos++; // Skip '=' - Param->Value.Start = CurPos; if (CurPos < Gbl.Params.ContentLength) { + Param->Value.Start = CurPos; Param->Value.Length = strcspn (&Gbl.Params.QueryString[CurPos],"&"); CurPos += Param->Value.Length; if (CurPos < Gbl.Params.ContentLength) if (Gbl.Params.QueryString[CurPos] == '&') CurPos++; // Skip '&' } - else - Param->Value.Length = 0; } - else - { - Param->Value.Start = CurPos; - Param->Value.Length = 0; - } - } - else - { - Param->Value.Start = CurPos; - Param->Value.Length = 0; - } } } @@ -263,9 +261,172 @@ static void Par_CreateListOfParamsFromQueryString (void) /*****************************************************************************/ // TODO: Rename Gbl.F.Tmp to Gbl.F.In (InFile, QueryFile)? +#define Par_MAX_BYTES_STR_AUX 1024 + static void Par_CreateListOfParamsFromTmpFile (void) { - // TODO: Implement + static const char *StringBeforeParam = "Content-Disposition: form-data; name=\""; +#define Par_LENGTH_OF_STR_BEFORE_PARAM 38 // Length of "Content-Disposition: form-data; name=\"" + static const char *StringFilename = "; filename=\""; +#define Par_LENGTH_OF_STR_FILENAME 12 // Length of "; filename=\"" + static const char *StringContentType = "Content-Type: "; +#define Par_LENGTH_OF_STR_CONTENT_TYPE 14 // Length of "Content-Type: " + + unsigned long CurPos; // Current position in query string + struct Param *Param; + struct Param *NewParam; + int Result; + int Ch; + char StrAux[Par_MAX_BYTES_STR_AUX+1]; + + /***** Check if file is empty *****/ + Gbl.Params.List = NULL; + if (!Gbl.Params.ContentLength) + return; + + /***** Go over the file + getting start positions and lengths of parameters *****/ + Result = Str_SkipFileUntilDelimitStr (Gbl.F.Tmp,Gbl.DelimiterString); + if (Result == 1) // Delimiter string found + for (CurPos = 0; + CurPos < Gbl.Params.ContentLength; + ) + { + /***** Skip \r\n after delimiter string *****/ + if (fgetc (Gbl.F.Tmp) != 0x0D) // '\r' + break; + if (fgetc (Gbl.F.Tmp) != 0x0A) // '\n' + break; + + Str_GetNextStrFromFileConvertingToLower (Gbl.F.Tmp,StrAux, + Par_LENGTH_OF_STR_BEFORE_PARAM); + if (!strcasecmp (StrAux,StringBeforeParam)) // Start of a parameter + { + /* Allocate space for a new parameter initialized to 0 */ + if ((NewParam = (struct Param *) calloc (1,sizeof (struct Param))) == NULL) + Lay_ShowErrorAndExit ("Error allocating memory for parameter"); + + /* Link the previous element in list with the current element */ + if (CurPos == 0) + Gbl.Params.List = NewParam; // Pointer to first param + else + Param->Next = NewParam; // Pointer from former param to new param + + /* Make the current element to be the just created */ + Param = NewParam; + + /***** Get parameter name *****/ + CurPos = (unsigned long) ftell (Gbl.F.Tmp); + Param->Name.Start = CurPos; + Ch = Par_ReadTmpFileUntilQuote (); + CurPos = (unsigned long) ftell (Gbl.F.Tmp); + Param->Name.Length = CurPos - Param->Name.Start; + + /* Check if last character read after parameter name is a quote */ + if (Ch != (int) '\"') + break; + + /* Get next char after parameter name */ + Ch = fgetc (Gbl.F.Tmp); + + /***** Check if filename is present *****/ + if (Ch == (int) StringFilename[0]) + { + Str_GetNextStrFromFileConvertingToLower (Gbl.F.Tmp,StrAux, + Par_LENGTH_OF_STR_FILENAME-1); + if (!strcasecmp (StrAux,StringFilename+1)) // Start of filename + { + /* Get filename */ + CurPos = (unsigned long) ftell (Gbl.F.Tmp); + Param->Filename.Start = CurPos; + Ch = Par_ReadTmpFileUntilQuote (); + CurPos = (unsigned long) ftell (Gbl.F.Tmp); + Param->Filename.Length = CurPos - Param->Filename.Start; + + /* Check if last character read after filename is a quote */ + if (Ch != (int) '\"') + break; + + /* Skip \r\n */ + if (fgetc (Gbl.F.Tmp) != 0x0D) // '\r' + break; + if (fgetc (Gbl.F.Tmp) != 0x0A) // '\n' + break; + + /* Check if Content-Type is present */ + Str_GetNextStrFromFileConvertingToLower (Gbl.F.Tmp,StrAux, + Par_LENGTH_OF_STR_CONTENT_TYPE); + if (!strcasecmp (StrAux,StringContentType)) // Start of Content-Type + { + /* Get content type */ + CurPos = (unsigned long) ftell (Gbl.F.Tmp); + Param->ContentType.Start = CurPos; + Ch = Par_ReadTmpFileUntilReturn (); + CurPos = (unsigned long) ftell (Gbl.F.Tmp); + Param->ContentType.Length = CurPos - Param->Filename.Start; + } + } + } + + /***** Now \r\n\r\n is expected just before parameter value or file content *****/ + /* Check if last character read is '\r' */ + if (Ch != 0x0D) + break; + + /* Skip \n\r\n */ + if (fgetc (Gbl.F.Tmp) != 0x0A) // '\n' + break; + if (fgetc (Gbl.F.Tmp) != 0x0D) // '\r' + break; + if (fgetc (Gbl.F.Tmp) != 0x0A) // '\n' + break; + + /***** Get parameter value or file content *****/ + CurPos = (unsigned long) ftell (Gbl.F.Tmp); + Result = Str_SkipFileUntilDelimitStr (Gbl.F.Tmp,Gbl.DelimiterString); + if (Result != 1) // Delimiter string not found + break; + + // Delimiter string found + Param->Value.Start = CurPos; + CurPos = (unsigned long) ftell (Gbl.F.Tmp); + Param->Value.Length = CurPos - Param->Filename.Start; + } + } + } + +/*****************************************************************************/ +/******************** Read from file until quote '\"' ************************/ +/*****************************************************************************/ +// Return last char read + +static int Par_ReadTmpFileUntilQuote (void) + { + int Ch; + + /***** Read until quote if found *****/ + do + Ch = fgetc (Gbl.F.Tmp); + while (Ch != EOF && Ch != (int) '\"'); + + return Ch; + } + +/*****************************************************************************/ +/*************************** Read from file until \r *************************/ +/*****************************************************************************/ +// Return last char read + +static int Par_ReadTmpFileUntilReturn (void) + { + int Ch; + + /***** Read until \r if found *****/ + do + Ch = fgetc (Gbl.F.Tmp); + while (Ch != EOF && Ch != 0x0D); // '\r' + + return Ch; } /*****************************************************************************/ @@ -296,9 +457,6 @@ void Par_FreeParams (void) /*****************************************************************************/ // 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 - unsigned Par_GetParameter (tParamType ParamType,const char *ParamName, char *ParamValue,size_t MaxBytes) { @@ -402,7 +560,7 @@ unsigned Par_GetParameter (tParamType ParamType,const char *ParamName, case -1: // Delimiter string not found ContinueSearching = false; break; - case 0: // Par_MAX_BYTES_STR_AUX exceeded + case 0: // Fil_MAX_FILE_SIZE exceeded ContinueSearching = false; break; case 1: // Delimiter string found diff --git a/swad_parameter.h b/swad_parameter.h index 82abac62..0305494e 100644 --- a/swad_parameter.h +++ b/swad_parameter.h @@ -41,8 +41,10 @@ struct StartLength }; struct Param { - struct StartLength Name; - struct StartLength Value; + struct StartLength Name; // Parameter name + struct StartLength Filename; // optional + struct StartLength ContentType; // optional + struct StartLength Value; // Parameter value or file content struct Param *Next; }; diff --git a/swad_string.c b/swad_string.c index 9e617110..fe3ff580 100644 --- a/swad_string.c +++ b/swad_string.c @@ -2581,6 +2581,55 @@ int Str_ReceiveFileUntilDelimitStr (FILE *FileSrc, FILE *FileTgt, char *StrDst, return 0; // Not reached } +int Str_SkipFileUntilDelimitStr (FILE *FileSrc, const char *StrDelimit) + { + int NumBytesIdentical; // Number of characters identical in each iteration of the loop + int NumBytesReadButNoWritten = 0; // Number of characters read from the source file + // and not written in the destination file + int LengthStrDelimit = strlen (StrDelimit); + int Buffer[MAX_LENGTH_STR_DELIMIT+1]; + int StartIndex = 0; + int i; + + if (LengthStrDelimit == 0 || + LengthStrDelimit > MAX_LENGTH_STR_DELIMIT) + Lay_ShowErrorAndExit ("Wrong delimiter string."); + + for (;;) + { + if (!NumBytesReadButNoWritten) + { // Read next character + Buffer[StartIndex] = fgetc (FileSrc); + if (feof (FileSrc)) + return -1; + NumBytesReadButNoWritten++; + } + if (Buffer[StartIndex] == (int) StrDelimit[0]) // First character identical + { + for (NumBytesIdentical = 1, i = (StartIndex + 1) % LengthStrDelimit; + NumBytesIdentical < LengthStrDelimit; + NumBytesIdentical++, i = (i + 1) % LengthStrDelimit) + { + if (NumBytesReadButNoWritten == NumBytesIdentical) // Next character identical + { + Buffer[i] = fgetc (FileSrc); // Read next character + if (feof (FileSrc)) + return -1; + NumBytesReadButNoWritten++; + } + if (Buffer[i] != (int) StrDelimit[NumBytesIdentical]) // Next different character + break; + } + if (NumBytesIdentical == LengthStrDelimit) // Str found + return 1; + } + NumBytesReadButNoWritten--; + StartIndex = (StartIndex+1) % LengthStrDelimit; + } + + return 0; // Not reached + } + /*****************************************************************************/ /****** Convert invalid characters in a file name to valid characters ********/ /*****************************************************************************/ diff --git a/swad_string.h b/swad_string.h index 844fa0c7..922e0f82 100644 --- a/swad_string.h +++ b/swad_string.h @@ -108,7 +108,8 @@ bool Str_FileIsHTML (const char *FileName); bool Str_Path1BeginsByPath2 (const char *Path1,const char *Path2); void Str_SkipSpacesInFile (FILE *FileSrc); void Str_FilePrintStrChangingBRToRetAndNBSPToSpace (FILE *FileTgt,const char *Str); -int Str_ReceiveFileUntilDelimitStr (FILE *FileSrc, FILE *FileTgt, char *StrDst, const char *StrDelimit, unsigned long long MaxLength); +int Str_ReceiveFileUntilDelimitStr (FILE *FileSrc, FILE *FileTgt, char *StrDst, const char *StrDelimit, unsigned long long MaxLength); +int Str_SkipFileUntilDelimitStr (FILE *FileSrc, const char *StrDelimit); bool Str_ConvertFilFolLnkNameToValid (char *FileName); void Str_ConvertToValidFileName (char *Str); void Str_WriteSizeInBytesBrief (double SizeInBytes);