Force a session close in MQX 3.8 httpd Server?

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 
已解决

Force a session close in MQX 3.8 httpd Server?

跳至解决方案
1,469 次查看
Tim562
Senior Contributor I

Hi All,

 

     I'm wondering if it's possible to force the closure of an MQX 3.8 httpd server session?

 

     I have a cgi function that is called to service an http POST file upload from a form served by the httpd server. Things all seem to go well, I receive the file, do what I need to do with it and issue a response that basically says "I got the file, great job, thanks......" The response is properly displayed but the browser window showing the response page indicates it's waiting for something (that it never gets). Also, I think, the httpd server never closes the session. I think this because if I do this twice (2 is the max sessions value in the httpd server) the web server stops responding to all new requests until the system is rebooted.

 

     I either need to figure out what is missing from my response (what is the browser window still waiting for) or how to force the termination of the session when this happens. Anybody have any experience in this area? Thanks!

 

~Tim

标签 (1)
标记 (1)
0 项奖励
1 解答
489 次查看
Tim562
Senior Contributor I

Problem solved,

 

     As is usually the case, the problem wasn't where it appeared to be and had a much simpler explaination. The string buffer I was using to create the webpage reply to the http POST message was too small for the amount of data I Was trying to stuff into it and I overran it. Some days your the bat and some days......

 

     Anyways, I have a properly working file upload from a MQX httpd served webpage to my TWR-MPC-5125 product. It was a pain to figure out so if anyone else needs to do this, reply here and I will post the server/client side code.

 

~Tim

在原帖中查看解决方案

0 项奖励
5 回复数
490 次查看
Tim562
Senior Contributor I

Problem solved,

 

     As is usually the case, the problem wasn't where it appeared to be and had a much simpler explaination. The string buffer I was using to create the webpage reply to the http POST message was too small for the amount of data I Was trying to stuff into it and I overran it. Some days your the bat and some days......

 

     Anyways, I have a properly working file upload from a MQX httpd served webpage to my TWR-MPC-5125 product. It was a pain to figure out so if anyone else needs to do this, reply here and I will post the server/client side code.

 

~Tim

0 项奖励
489 次查看
dspNeil
Contributor III

Tim,

I'm going to be doing something similar on a future release of my software. If you can provide some example code, I'd be very appreciative.

Thanks,

Neil

0 项奖励
489 次查看
Tim562
Senior Contributor I

 

Hi Neil,

 

      Glad to help. First, on your webpage that will upload the binary file, place a form with a file upload/selection object in it like this:

  

<form name="image_form" enctype="multipart/form-data" method="post" target="_blank" action="http:recv_image.cgi" onsubmit="upld_img_btn()">    <input title="Click to choose a file" type="file" id="img_file" name="img_file" />    <input type="button" value="Upload New Image" onclick="upld_img_btn()"  /></form>

 

The action field "http:recv_image" specifies the name of the cgi function that will be called by the MQX httpd server on my project to receive and process the uploaded file. You can refer to the HVAC demo for examples of how to specify which cgi functions are called.

 

 

I also used a clientside Javascript  function to actually perform the file upload from the webpage like this:

 

function upld_img_btn()   {   var filepath_str = document.getElementById("img_file").value   if(filepath_str == "")      {      alert("No File Selected. Please Select A Firmware Image File First.");      return;      }   var parsed = filepath_str.split( "\\" );   var iCount = parsed.length-1;   var filename_only = parsed[iCount];   var sPromptString = "WARNING - About To Upload System Firmware Image File[ " + filename_only + " ] Please Confirm Or Cancel";   var retval=confirm(sPromptString);   if(retval!=true)      return;   document.forms["image_form"].submit(); //Submit the image upload form data to the cgi function on your server   return;   }

 

Here's a stripped down version of the function running on my MQX project that is called by the MQX httpd server when the file is uploaded by the user. In my actual function, I use MQX functions to store the received file as a boot image in the image table and set it as active for the next reboot.

 

_mqx_int cgi_recv_image(HTTPD_SESSION_STRUCT *session)   {   boolean bMore2Come;   uint_8 cByte;   uint_16 iMsgIdStrngLength, iBoundaryLength;   _mqx_int lReadLength, lTotalRecvdMsgBytes, lBytesRead, lFileByteSize, lCount, lTemp, lWriteSize, lRetval = 0;   char_ptr sRecvBuffer = NULL;   char_ptr sBufferPtr = NULL;   char_ptr sBufferDataStartPtr = NULL;   char_ptr sBufferEndPtr = NULL;   char_ptr sTmpStrng = NULL;   char sFileNameStrng[gcMAX_MSGSTRNGSIZE+1];//Allocate some temp buffers//----------------------------------------------------------------------------   lTotalRecvdMsgBytes = session->request.content_len;   if(lTotalRecvdMsgBytes == 0)      return(0);     sRecvBuffer = _mem_alloc(lTotalRecvdMsgBytes);   if(sRecvBuffer == NULL)      {      //... Handle error here      return(0);      }   sTmpStrng = _mem_alloc(gc2K_STRING); //String needs to be large enough to store the http POST reply page   if(sTmpStrng == NULL)      {      //... Handle error here      return(0);      }//Read in the data until all bytes (per lTotalRecvdMsgBytes value) are received//----------------------------------------------------------------------------   sBufferPtr = sRecvBuffer; //Use sBufferPtr as a movable temp pointer so sRecvBuffer can always point to buffer start   lReadLength = httpd_read(session, sBufferPtr, lTotalRecvdMsgBytes); //Get any waiting bytes   lBytesRead = lReadLength; //Record how many bytes we extracted from the incoming stream   session->request.content_len -= lReadLength;   while(session->request.content_len > 0)   //Keep reading the incoming stream until all data bytes spec'd      {       //in session->request.content_len have been received      sBufferPtr += lReadLength;    //Advance buffer pointer to location where next bytes are to be stored      lReadLength = httpd_read(session, sBufferPtr, (lTotalRecvdMsgBytes - lBytesRead)); //Retreive waiting bytes from incoming stream      session->request.content_len -= lReadLength;      lBytesRead += lReadLength;      }//Example of header info that leads the http POST data sent by the webpage:////-----------------------------BoundaryString\r\nContent-Disposition: Form data: name="img_file"; filename="xxxxxxxx.xxx"\r\nContent-Type:application/octet stream\r\n\r\n//|_____________iBoundaryLength_____________|                                         |variable|            | variable |            --Actual Start Of Data Payload Here->///                                                                                      length                 length //Count the number of chars in the leading http encapsulation boundary string as per the above example://----------------------------------------------------------------------------   iBoundaryLength = 0;   sBufferPtr = sRecvBuffer; //Reset sBufferPtr to start of sRecvBuffer   while(*sBufferPtr != '\r') //Count the number of chars in the boundary string      {    //(String is finished at the \r\n chars)      sBufferPtr++;      iBoundaryLength++;       }//Calculate the number of bytes of the file data payload in the received string//----------------------------------------------------------------------------   sBufferPtr = NULL;   sBufferPtr = (char *)strstr(sRecvBuffer, "Content-Type"); //Find the start of the actual data which follows the Content-Type string   if(sBufferPtr == NULL)      {      //... Handle error here      _mem_free(sRecvBuffer);      _mem_free(sTmpStrng);      return(lRetval);      }    while(*sBufferPtr != '\r')  //Count the number of chars in the Content-Type string      sBufferPtr++;   //(string is finished at the \r\n\r\n chars)   sBufferPtr += 4;      //Advance sBufferPtr past the \r\n\r\n chars to the actual start of the file data   sBufferDataStartPtr = sBufferPtr;     //Remember this location for later use   lTemp = sBufferPtr - sRecvBuffer;     //Determine how many chars preceeded the start of data   lFileByteSize = lTotalRecvdMsgBytes - lTemp;  //File size is total recvd bytes minus leading http header bytes   lFileByteSize -= (iBoundaryLength + 6);//and trailing http closing boundary(  "\r\n-----------------------------BoundaryString--\r\n" -END- )//                                          |_____________iBoundaryLength_____________|//Do what you need to with the data//----------------------------------------------------------------------------   sBufferEndPtr = sBufferPtr + lFileByteSize;   while(sBufferPtr < sBufferEndPtr)      {      }//Issue the all ok reply//----------------------------------------------------------------------------   sprintf(sTmpStrng, "Received %d Byte Firmware Image File[ %s ]\n", lFileByteSize, sFileNameStrng);   strcat(sTmpStrng, "<br/><br/>\n");   strcat(sTmpStrng, "This new firmware image has been stored into flash and recorded in the Image Table\n");   strcat(sTmpStrng, "<br/>\n");   strcat(sTmpStrng, "as the currently active firmware image. When the device is restarted this new image\n");   strcat(sTmpStrng, "<br/>\n");   strcat(sTmpStrng, "will be loaded into memory and started. If a different boot image image is desired \n");   strcat(sTmpStrng, "<br/>\n");   strcat(sTmpStrng, "you may select that image from the Router Firmware Control webpage.\n");   lRetval = cgi_SendResponseWindow(session, sTmpStrng);//Clean up and exit happy here//----------------------------------------------------------------------------   _mem_free(sRecvBuffer);   _mem_free(sTmpStrng);   return(lRetval);   }

 

 

Here's the cgi function that sends my reply to the web page. Since I added the "target="_blank" tag to my form, this reply will be displayed in a new window on the client computer.

 

_mqx_int cgi_SendResponseWindow(HTTPD_SESSION_STRUCT *session, char_ptr spString)   {   session->response.contenttype = CONTENT_TYPE_HTML;   httpd_sendhdr(session, 0, 0);   httpd_sendstr(session->sock, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n");   httpd_sendstr(session->sock, "<html>\n");   httpd_sendstr(session->sock, "<head>\n");   httpd_sendstr(session->sock, "<title>Firmware Image Upload Response</title>\n");   httpd_sendstr(session->sock, "<script type=\"text/javascript\">\n");   httpd_sendstr(session->sock, "function closeWin()\n");   httpd_sendstr(session->sock, "     {\n");   httpd_sendstr(session->sock, "     window.close();\n");   httpd_sendstr(session->sock, "     return;\n");   httpd_sendstr(session->sock, "     }\n");   httpd_sendstr(session->sock, "</script>\n");   httpd_sendstr(session->sock, "</head>\n");   httpd_sendstr(session->sock, "<body>\n");   httpd_sendstr(session->sock, "<br/><br/>\n");   httpd_sendstr(session->sock, spString);   httpd_sendstr(session->sock, "<br/><br/>\n");   httpd_sendstr(session->sock, "<br/><br/>\n");   httpd_sendstr(session->sock, "<input type=\"button\" value=\"Close This Window\" onclick=\"closeWin()\" />\n");   httpd_sendstr(session->sock, "</body>\n");   httpd_sendstr(session->sock, "</html>\n");   return(session->request.content_len);   }

 

I am pretty far from being an expert in this area so use this code at your own risk. It seems to work pretty well for me. Hope this helps.

 

Best Regards,

Tim

 

 

 

 

 

 

 

 

0 项奖励
489 次查看
shark
Contributor I

Hi Tim,

 

Thanks for your post on how to upload file through web page. I really looking for this solution. I will try to implement it. But through web page, is there any way to download the file from the TWR to the client PC?Hope you will help me on this one.

 

rgds,

Shark

0 项奖励
489 次查看
Tim562
Senior Contributor I

I haven't had to do that yet Shark. I'm sure it's possible though. If you do implement that maybe you could post your solution here for all of us to share!

 

Best,

Tim

0 项奖励