You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tcl.apache.org by mx...@apache.org on 2020/10/01 23:33:40 UTC
[tcl-rivet] 02/07: restructuring and testing new code of upload
command
This is an automated email from the ASF dual-hosted git repository.
mxmanghi pushed a commit to branch quattuor
in repository https://gitbox.apache.org/repos/asf/tcl-rivet.git
commit a918f36b1d5ac12b1f859a0e60951011eac6cc44
Author: Massimo Manghi <mx...@apache.org>
AuthorDate: Sat May 2 02:01:22 2020 +0200
restructuring and testing new code of upload command
---
src/TclWeb.h | 37 ++++----
src/mod_rivet_ng/TclWebapache.c | 150 ++++++++++++++++++--------------
src/mod_rivet_ng/rivetCore.c | 183 ++++++++++++++++++++--------------------
3 files changed, 199 insertions(+), 171 deletions(-)
diff --git a/src/TclWeb.h b/src/TclWeb.h
index dffec44..0de1ba9 100644
--- a/src/TclWeb.h
+++ b/src/TclWeb.h
@@ -158,17 +158,17 @@ int TclWeb_PrepareUpload(char *varname, TclWebRequest *req);
*
* TclWeb_UploadChannel --
*
- * Takes the address of a Tcl_Channel and uses it to create a channel
- * pointing to the upload data.
+ * It opens a new channel and sets its translation and encoding as binary
+ * The channel name is retuned as result in the interpreter pointed by req->interp
*
* Results:
*
- * 'chan' points to a FileChannel containing the uploaded data.
+ * Makes the channel name available to the script level
*
*-----------------------------------------------------------------------------
*/
-int TclWeb_UploadChannel(char *varname, Tcl_Channel *chan, TclWebRequest *req);
+int TclWeb_UploadChannel(char *varname, TclWebRequest *req);
/*
*-----------------------------------------------------------------------------
@@ -187,68 +187,71 @@ int TclWeb_UploadSave(char *varname, Tcl_Obj *filename, TclWebRequest *req);
*
* TclWeb_UploadData --
*
- * Fills in the 'data' Tcl_Obj with the uploaded data.
+ * Returns the uploaded data to the Tcl script level.
+ *
+ * If the config parameter upload_files_to_var is not set the procedure
+ * returs an error
*
*-----------------------------------------------------------------------------
*/
-int TclWeb_UploadData(char *varname, Tcl_Obj *data, TclWebRequest *req);
+int TclWeb_UploadData(char *varname, TclWebRequest *req);
/*
*-----------------------------------------------------------------------------
*
* TclWeb_UploadSize --
*
- * Stores, in 'sz' the size of the data uploaded.
+ * Returns the size of the data uploaded.
*
*-----------------------------------------------------------------------------
*/
-int TclWeb_UploadSize(Tcl_Obj *sz, TclWebRequest *req);
+int TclWeb_UploadSize(TclWebRequest *req);
/*
*-----------------------------------------------------------------------------
*
* TclWeb_UploadType --
*
- * Stores, in 'type' the mime type of the file uploaded.
+ * Returns the mime type of the file uploaded.
*
*-----------------------------------------------------------------------------
*/
-int TclWeb_UploadType(Tcl_Obj *type, TclWebRequest *req);
+int TclWeb_UploadType(TclWebRequest *req);
/*
*-----------------------------------------------------------------------------
*
* TclWeb_UploadFilename --
*
- * Get the original filename of the uploaded data, on the client side.
+ * Returns the original filename of the uploaded data, on the client side.
*
* Results:
*
- * Stores the filename in 'filename'.
+ * Returns the filename to the script level
*
*-----------------------------------------------------------------------------
*/
-int TclWeb_UploadFilename(Tcl_Obj *filename, TclWebRequest *req);
+int TclWeb_UploadFilename(TclWebRequest *req);
/*
*-----------------------------------------------------------------------------
*
* TclWeb_UploadTempname --
*
- * Get the name of the temp file the uploaded data was stored in.
+ * Returns the name of the temp file the uploaded data was stored in.
*
* Results:
*
- * Stores the temp name in 'tempname'.
+ * the 'tempname' is returned to the script level
*
*-----------------------------------------------------------------------------
*/
-int TclWeb_UploadTempname(Tcl_Obj *tempname, TclWebRequest *req);
+int TclWeb_UploadTempname(TclWebRequest *req);
/*
*-----------------------------------------------------------------------------
@@ -264,7 +267,7 @@ int TclWeb_UploadTempname(Tcl_Obj *tempname, TclWebRequest *req);
*-----------------------------------------------------------------------------
*/
-int TclWeb_UploadNames(Tcl_Obj *names, TclWebRequest *req);
+int TclWeb_UploadNames(TclWebRequest *req);
int TclWeb_Escape(char *out, char *in, int len, void *var);
diff --git a/src/mod_rivet_ng/TclWebapache.c b/src/mod_rivet_ng/TclWebapache.c
index d755507..9d573ee 100644
--- a/src/mod_rivet_ng/TclWebapache.c
+++ b/src/mod_rivet_ng/TclWebapache.c
@@ -314,7 +314,7 @@ TclWeb_GetVar(Tcl_Obj *result, char *varname, int source, TclWebRequest *req)
if (result->length == 0)
{
- return TCL_ERROR;
+ return TCL_ERROR;
}
return TCL_OK;
@@ -334,19 +334,19 @@ TclWeb_GetVarAsList(Tcl_Obj *result, char *varname, int source, TclWebRequest *r
while (i < j)
{
- if (!strncmp(varname, TclWeb_StringToUtf(parms[i].key, req),
- strlen(varname) < strlen(parms[i].key) ?
- strlen(parms[i].key) : strlen(varname)))
- {
- Tcl_ListObjAppendElement(req->interp, result,
- TclWeb_StringToUtfToObj(parms[i].val, req));
- }
- i++;
+ if (!strncmp(varname, TclWeb_StringToUtf(parms[i].key, req),
+ strlen(varname) < strlen(parms[i].key) ?
+ strlen(parms[i].key) : strlen(varname)))
+ {
+ Tcl_ListObjAppendElement(req->interp, result,
+ TclWeb_StringToUtfToObj(parms[i].val, req));
+ }
+ i++;
}
if (result == NULL)
{
- return TCL_ERROR;
+ return TCL_ERROR;
}
return TCL_OK;
}
@@ -660,47 +660,59 @@ int TclWeb_PrepareUpload(char *varname, TclWebRequest *req)
}
}
-int TclWeb_UploadChannel(char *varname, Tcl_Channel *chan, TclWebRequest *req)
+int TclWeb_UploadChannel(char *varname, TclWebRequest *req)
{
- *chan = Tcl_OpenFileChannel (req->interp, req->upload->tempname, "r", 0);
+ Tcl_Channel chan;
+
+ chan = Tcl_OpenFileChannel(req->interp, req->upload->tempname, "r", 0);
+
if (chan == NULL) {
- return TCL_ERROR;
- } else {
- if (Tcl_SetChannelOption(req->interp, *chan,
- "-translation", "binary") == TCL_ERROR) {
- return TCL_ERROR;
- }
- if (Tcl_SetChannelOption(req->interp, *chan,
- "-encoding", "binary") == TCL_ERROR) {
return TCL_ERROR;
- }
- Tcl_RegisterChannel (req->interp, *chan);
- return TCL_OK;
+ } else {
+ Tcl_Obj* result;
+
+ if (Tcl_SetChannelOption(req->interp,chan,"-translation","binary") == TCL_ERROR) {
+ return TCL_ERROR;
+ }
+ if (Tcl_SetChannelOption(req->interp,chan,"-encoding","binary") == TCL_ERROR) {
+ return TCL_ERROR;
+ }
+ Tcl_RegisterChannel(req->interp,chan);
+
+ result = Tcl_NewObj();
+ Tcl_SetStringObj(result, Tcl_GetChannelName(chan), -1);
+ Tcl_SetObjResult(req->interp, result);
+
+ return TCL_OK;
}
}
-int TclWeb_UploadTempname(Tcl_Obj *tempname, TclWebRequest *req)
+int TclWeb_UploadTempname(TclWebRequest *req)
{
- Tcl_SetStringObj(tempname,
- TclWeb_StringToUtf(req->upload->tempname,
- req), -1);
+ Tcl_Obj *tempname = Tcl_NewObj();
+
+ Tcl_SetStringObj(tempname,TclWeb_StringToUtf(req->upload->tempname,req), -1);
+ Tcl_SetObjResult(req->interp, tempname);
+
return TCL_OK;
}
int TclWeb_UploadSave(char *varname, Tcl_Obj *filename, TclWebRequest *req)
{
- apr_status_t status;
+ apr_status_t status;
+
status = apr_file_copy(req->upload->tempname ,Tcl_GetString(filename),APR_FILE_SOURCE_PERMS,req->req->pool);
- if ( status == 0 ) {
+ if (status == APR_SUCCESS) {
return TCL_OK;
} else {
return TCL_ERROR;
}
}
-int TclWeb_UploadData(char *varname, Tcl_Obj *data, TclWebRequest *req)
+int TclWeb_UploadData(char *varname, TclWebRequest *req)
{
+ Tcl_Obj* result;
rivet_server_conf *rsc = NULL;
rsc = RIVET_SERVER_CONF( req->req->server->module_config );
@@ -708,68 +720,80 @@ int TclWeb_UploadData(char *varname, Tcl_Obj *data, TclWebRequest *req)
get everything fixed and working first */
if (rsc->upload_files_to_var)
{
- Tcl_Channel chan;
- chan = Tcl_OpenFileChannel (req->interp, req->upload->tempname, "r", 0);
- if (chan == NULL) {
- return TCL_ERROR;
- }
- if (Tcl_SetChannelOption(req->interp, chan,
- "-translation", "binary") == TCL_ERROR) {
- return TCL_ERROR;
- }
- if (Tcl_SetChannelOption(req->interp, chan,
- "-encoding", "binary") == TCL_ERROR) {
- return TCL_ERROR;
- }
+ Tcl_Channel chan;
+
+ chan = Tcl_OpenFileChannel (req->interp, req->upload->tempname, "r", 0);
+ if (chan == NULL) {
+ return TCL_ERROR;
+ }
+ if (Tcl_SetChannelOption(req->interp, chan,
+ "-translation", "binary") == TCL_ERROR) {
+ return TCL_ERROR;
+ }
+ if (Tcl_SetChannelOption(req->interp, chan,
+ "-encoding", "binary") == TCL_ERROR) {
+ return TCL_ERROR;
+ }
- /* Put data in a variable */
- Tcl_ReadChars(chan, data, (int)ApacheUpload_size(req->upload), 0);
- if (Tcl_Close(req->interp, chan) == TCL_ERROR) {
- return TCL_ERROR;
- }
+ /* Put data in a variable */
+ result = Tcl_NewObj();
+ Tcl_ReadChars(chan, result, (int)ApacheUpload_size(req->upload), 0);
+ if (Tcl_Close(req->interp, chan) == TCL_ERROR) {
+ return TCL_ERROR;
+ }
+
+ Tcl_SetObjResult(req->interp, result);
} else {
- Tcl_AppendResult(req->interp,
- "RivetServerConf UploadFilesToVar is not set", NULL);
- return TCL_ERROR;
+ Tcl_AppendResult(req->interp,
+ "RivetServerConf UploadFilesToVar is not set", NULL);
+ return TCL_ERROR;
}
+
return TCL_OK;
}
-int TclWeb_UploadSize(Tcl_Obj *sz, TclWebRequest *req)
+int TclWeb_UploadSize(TclWebRequest *req)
{
- Tcl_SetIntObj(sz, (int)ApacheUpload_size(req->upload));
+ Tcl_Obj* result = Tcl_NewObj();
+ Tcl_SetIntObj(result, (int)ApacheUpload_size(req->upload));
+ Tcl_SetObjResult(req->interp, result);
return TCL_OK;
}
-int TclWeb_UploadType(Tcl_Obj *type, TclWebRequest *req)
+int TclWeb_UploadType(TclWebRequest *req)
{
+ Tcl_Obj *type = Tcl_NewObj();
+
/* If there is a type, return it, if not, return blank. */
Tcl_SetStringObj(type, ApacheUpload_type(req->upload)
? (char *)ApacheUpload_type(req->upload) : (char *)"", -1);
+
+ Tcl_SetObjResult(req->interp, type);
return TCL_OK;
}
-int TclWeb_UploadFilename(Tcl_Obj *filename, TclWebRequest *req)
+int TclWeb_UploadFilename(TclWebRequest *req)
{
- Tcl_SetStringObj(filename,
- TclWeb_StringToUtf(req->upload->filename,
- req), -1);
+ Tcl_Obj *filename = Tcl_NewObj();
+ Tcl_SetStringObj(filename,TclWeb_StringToUtf(req->upload->filename,req), -1);
+
+ Tcl_SetObjResult(req->interp, filename);
return TCL_OK;
}
-int TclWeb_UploadNames(Tcl_Obj *names, TclWebRequest *req)
+int TclWeb_UploadNames(TclWebRequest *req)
{
ApacheUpload *upload;
+ Tcl_Obj *names = Tcl_NewObj();
upload = ApacheRequest_upload(req->apachereq);
while (upload)
{
- Tcl_ListObjAppendElement(
- req->interp, names,
- TclWeb_StringToUtfToObj(upload->name,req));
- upload = upload->next;
+ Tcl_ListObjAppendElement(req->interp,names,TclWeb_StringToUtfToObj(upload->name,req));
+ upload = upload->next;
}
+ Tcl_SetObjResult(req->interp,names);
return TCL_OK;
}
diff --git a/src/mod_rivet_ng/rivetCore.c b/src/mod_rivet_ng/rivetCore.c
index 0679bff..5dc9a1b 100644
--- a/src/mod_rivet_ng/rivetCore.c
+++ b/src/mod_rivet_ng/rivetCore.c
@@ -1017,22 +1017,12 @@ TCL_CMD_HEADER( Rivet_ApacheTable )
return TCL_OK;
}
-
/*
*-----------------------------------------------------------------------------
*
* Rivet_Upload --
*
- * Deals with file uploads (multipart/form-data) like so:
- *
- * upload channel uploadname
- * upload save name uploadname
- * upload data uploadname
- * upload exists uploadname
- * upload size uploadname
- * upload type uploadname
- * upload filename uploadname
- * upload names
+ * Deals with file uploads (multipart/form-data):
*
* Results:
* A standard Tcl result.
@@ -1049,7 +1039,29 @@ TCL_CMD_HEADER( Rivet_Upload )
char* varname = NULL;
int subcommandindex;
- Tcl_Obj* result = NULL;
+ /* ::rivet::upload subcommands must register
+ *
+ * - subcommand definition
+ * - subcommand integer progressive index
+ * - subcommand required (minimum) number of arguments
+ *
+ * +----------------------------------------+-------+
+ * | argv[1] argv[2] argv[3] | argc |
+ * +----------------------------------------+-------+
+ * | upload channel uploadname | 3 |
+ * | upload save uploadname filename | 4 |
+ * | upload data uploadname | 3 |
+ * | upload exists uploadname | 3 |
+ * | upload size uploadname | 3 |
+ * | upload type uploadname | 3 |
+ * | upload filename uploadname | 3 |
+ * | upload tempname uploadname | 3 |
+ * | upload names | 2 |
+ * +----------------------------------------+-------+
+ *
+ * a subcommand first optional argument must be the name
+ * of an upload
+ */
static CONST84 char *SubCommand[] = {
"channel",
@@ -1076,115 +1088,104 @@ TCL_CMD_HEADER( Rivet_Upload )
NAMES
};
- rivet_thread_private* private;
+ static CONST84 int cmds_objc[] = { 3,4,3,3,3,3,3,3,2 };
+ int expected_objc;
+
+ rivet_thread_private* private;
THREAD_PRIVATE_DATA(private)
CHECK_REQUEST_REC(private,"::rivet::upload")
if (Tcl_GetIndexFromObj(interp, objv[1], SubCommand,
- "channel|save|data|exists|size|type|filename|names|tempname"
- "|tempname|names",
+ "channel|save|data|exists|size|type|filename|tempname|names",
0, &subcommandindex) == TCL_ERROR) {
return TCL_ERROR;
}
- /* If it's any of these, we need to find a specific name. */
+ expected_objc = cmds_objc[subcommandindex];
- /* Excluded case is NAMES. */
+ if (objc != expected_objc) {
+ Tcl_Obj* infoobj = Tcl_NewStringObj("Wrong argument numbers: ",-1);
- if ((enum subcommand)subcommandindex == CHANNEL ||
- (enum subcommand)subcommandindex == SAVE ||
- (enum subcommand)subcommandindex == DATA ||
- (enum subcommand)subcommandindex == EXISTS ||
- (enum subcommand)subcommandindex == SIZE ||
- (enum subcommand)subcommandindex == TYPE ||
- (enum subcommand)subcommandindex == FILENAME ||
- (enum subcommand)subcommandindex == TEMPNAME)
- {
+ Tcl_IncrRefCount(infoobj);
+ Tcl_AppendObjToObj(infoobj,Tcl_NewIntObj(expected_objc));
+ Tcl_AppendStringsToObj(infoobj," arguments expected");
+ Tcl_AppendObjToErrorInfo(interp, infoobj);
+ Tcl_DecrRefCount(infoobj);
+
+ if (subcommandindex == SAVE) {
+ Tcl_WrongNumArgs(interp, 2, objv, "uploadname filename");
+ } else {
+ Tcl_WrongNumArgs(interp, objc, objv, "uploadname");
+ }
+ return TCL_ERROR;
+ }
+
+ /* We check whether an upload with a given name exists */
+
+ if (objc >= 3) {
+ int tcl_status;
varname = Tcl_GetString(objv[2]);
- if ((enum subcommand)subcommandindex != EXISTS)
- {
- if (TclWeb_PrepareUpload(varname, private->req) != TCL_OK)
- {
- Tcl_AddErrorInfo(interp, "Unable to find variable");
- return TCL_ERROR;
- }
+
+ /* TclWeb_PrepareUpload calls ApacheUpload_find and returns
+ * TCL_OK if the named upload exists in the current request */
+ tcl_status = TclWeb_PrepareUpload(varname, private->req);
+
+ if (subcommandindex == EXISTS) {
+ Tcl_Obj* result = NULL;
+ int upload_prepared = 0;
+
+ if (tcl_status == TCL_OK) upload_prepared = 1;
+
+ result = Tcl_NewObj();
+ Tcl_SetIntObj(result,upload_prepared);
+ Tcl_SetObjResult(interp, result);
+ return TCL_OK;
+
}
- /* If it's not the 'save' command, then it has to have an objc
- of 3. */
- if ((enum subcommand)subcommandindex != SAVE && objc != 3)
+ if (tcl_status != TCL_OK)
{
- Tcl_WrongNumArgs(interp, 2, objv, "varname");
+ Tcl_AddErrorInfo(interp, "Unable to find the upload named '");
+ Tcl_AppendObjToErrorInfo(interp,Tcl_NewStringObj(varname,-1));
+ Tcl_AppendObjToErrorInfo(interp,Tcl_NewStringObj("'",-1));
return TCL_ERROR;
}
}
- result = Tcl_NewObj();
+ /* CHANNEL : get the upload channel name
+ * SAVE : save data to a specified filename
+ * DATA : get the uploaded data into a Tcl variable
+ * SIZE : uploaded data size
+ * TYPE : upload mimetype
+ * FILENAME : upload original filename
+ * TEMPNAME : temporary file where the upload is taking place
+ * NAMES : list of uploads
+ *
+ * the procedure shouldn't reach for the default case
+ */
switch ((enum subcommand)subcommandindex)
{
- case CHANNEL: {
- Tcl_Channel chan;
- char *channelname = NULL;
-
- if (TclWeb_UploadChannel(varname, &chan, private->req) != TCL_OK) {
- return TCL_ERROR;
- }
- channelname = (char *)Tcl_GetChannelName(chan);
- Tcl_SetStringObj(result, channelname, -1);
- break;
- }
+ case CHANNEL:
+ return TclWeb_UploadChannel(varname, private->req);
case SAVE:
- /* save data to a specified filename */
- if (objc != 4) {
- Tcl_WrongNumArgs(interp, 2, objv, "uploadname filename");
- return TCL_ERROR;
- }
-
- if (TclWeb_UploadSave(varname, objv[3], private->req) != TCL_OK)
- {
- return TCL_ERROR;
- }
- break;
+ return TclWeb_UploadSave(varname, objv[3], private->req);
case DATA:
- if (TclWeb_UploadData(varname, result, private->req) != TCL_OK) {
- return TCL_ERROR;
- }
- break;
- case EXISTS:
- if (TclWeb_PrepareUpload(varname, private->req) != TCL_OK)
- {
- Tcl_SetIntObj(result, 0);
- } else {
- Tcl_SetIntObj(result, 1);
- }
- break;
+ return TclWeb_UploadData(varname, private->req);
case SIZE:
- TclWeb_UploadSize(result, private->req);
- break;
+ return TclWeb_UploadSize(private->req);
case TYPE:
- TclWeb_UploadType(result, private->req);
- break;
+ return TclWeb_UploadType(private->req);
case FILENAME:
- TclWeb_UploadFilename(result, private->req);
- break;
+ return TclWeb_UploadFilename(private->req);
case TEMPNAME:
- TclWeb_UploadTempname(result,private->req);
- break;
+ return TclWeb_UploadTempname(private->req);
case NAMES:
- if (objc != 2)
- {
- Tcl_WrongNumArgs(interp, 1, objv, "names");
- return TCL_ERROR;
- }
- TclWeb_UploadNames(result, private->req);
- break;
+ return TclWeb_UploadNames(private->req);
default:
- Tcl_WrongNumArgs(interp, 1, objv,
- "channel|save ?name?|data|exists|size|type|filename|names|tempname");
+ Tcl_WrongNumArgs(interp, 1, objv,"Rivet internal error: inconsistent argument");
}
- Tcl_SetObjResult(interp, result);
- return TCL_OK;
+ return TCL_ERROR;
}
/*
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@tcl.apache.org
For additional commands, e-mail: commits-help@tcl.apache.org