File Upload Issue

Post here your questions about SFS2X. Here we discuss all server-side matters. For client API questions see the dedicated forums.

Moderators: Lapo, Bax

Post Reply
timothyhermawan
Posts: 8
Joined: 10 Dec 2021, 10:47

File Upload Issue

Post by timothyhermawan »

Smartfox Version is 2.19.0

I was trying to upload a file from Unity client (image) and receive this errors:

Code: Select all

SEVERE: Servlet.service() for servlet [sfs2x.ws.tomcat.upload.HttpUploadManager] in context with path [/BlueBox] threw exception [Upload Refused from: 103.119.50.79 Missing valid session token.] with root cause
javax.servlet.ServletException: Upload Refused from: 103.119.50.79 Missing valid session token.


It was worked from the first time I created this feature on the game and suddenly throw this error.

From the logged in IP, and when the error thrown, I see a different IP between those two logs:

When Logged In, the IP is 103.119.50.21:60293
But when I tried to upload, it refused the IP 103.119.50.79

Code: Select all

05:44:17,262 INFO  [SFSWorker:Ext:4] api.SFSApi     - User login: { Zone: SlimeHaven }, ( User Name: Timmy_Guest_PC, Id: 0, Priv: 1, Sess: 103.119.50.21:60293 ) , Type: .Net
Jun 17, 2024 5:44:30 AM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [sfs2x.ws.tomcat.upload.HttpUploadManager] in context with path [/BlueBox] threw exception [Upload Refused from: 103.119.50.79 Missing valid session token.] with root cause
javax.servlet.ServletException: Upload Refused from: 103.119.50.79 Missing valid session token.


and here is the uploadURI that I debug:
http://34.101.228.88:8080/BlueBox/SFS2XFileUpload?sessHashId=961948c428165ab6d1f4f1bde95458ab&__uid=666165156c143006f545f0f9&__pid=65c32bc4b1da1b094761b926

I can confirm that the sessHashId does match when the user logged in to the custom login handler.

I also already toggle on-off the "Enable X forward" in the Server Configuration but still receive this error

Here is the client code:

Code: Select all

IEnumerator IEUploadSlime(Texture2D texture, string uploadURL, Action OnSuccess = null, Action<string> OnFail = null)
{
    this.texture = texture;

    Debug.Log($"SFS SessionToken: {SmartfoxManager.Instance.sfs.SessionToken}");

    Debug.Log($"Starting to upload. URL: {uploadURL}");

    WWWForm postForm = new WWWForm();
    postForm.AddBinaryData("theFile", texture.EncodeToPNG(), "full-transparent.png", "application/octet-stream");

    WWW upload = new WWW(uploadURL, postForm);
    yield return upload;

    if (upload.error == null)
    {
        Debug.Log("Upload done :" + upload.text);
        OnSuccess?.Invoke();
    }
    else
    {
        Debug.LogError("Error during upload: " + upload.error);
        OnFail?.Invoke(upload.error);
    }
}


and here is the server code:

Code: Select all

public class UploadImageHandler extends BaseServerEventHandler {

   static String Destination= "/home/timothyhermawan/SmartFoxServer_2X/SFS2X/www/ROOT/characters/";
   
   @Override
    public void handleServerEvent(ISFSEvent event) throws SFSException
    {
      
      System.out.println("========STARTING UPLOAD==============================");
      
        User sender = (User) event.getParameter(SFSEventParam.USER);
        List<UploadedFile> upFiles = (List<UploadedFile>) event.getParameter(SFSEventParam.UPLOAD_FILE_LIST);
        Map<String, String> httpParams = (Map<String, String>) event.getParameter(SFSEventParam.UPLOAD_HTTP_PARAMS);
       
        String uid = httpParams.get("__uid");
        String pid = httpParams.get("__pid");
       
        ClientSession session = GeneralUtility.CreateNewClientSession();

        try
        {
           System.out.println("==============TRY=========================");

            BasicSmartFoxResponse response = CharacterManager.Instance().SetNFTImageCaptured(session, pid, uid);
            if(response.status != 1) return;           
           
//           System.out.println(response);           
           
           File theDir = [code][/code]new File(Destination);
           if (!theDir.exists()){
               theDir.mkdirs();
           }           

           File tempFile = new File(upFiles.get(0).getTempFilePath());
           
            File targetFile = new File(Destination + uid +"/" + upFiles.get(0).getOriginalName());             
           
            FileUtils.moveFile(tempFile, targetFile);
           
            session.commitTransaction();           
        }
        catch(IOException ioe)
        {
           System.out.println("==============CATCH=========================");
           session.abortTransaction();
            ioe.printStackTrace();
        }
        finally {
           session.close();
        }
    }

}


and here is the stack trace

Code: Select all

 at sfs2x.ws.tomcat.upload.HttpUploadManager.validateSession(HttpUploadManager.java:229)
        at sfs2x.ws.tomcat.upload.HttpUploadManager.doPost(HttpUploadManager.java:78)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:681)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
        at sfs2x.ws.tomcat.shared.WSUpgradeFilter.invoke(WSUpgradeFilter.java:75)
        at org.apache.catalina.valves.rewrite.RewriteValve.invoke(RewriteValve.java:555)
        at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:687)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1722)
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
        at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
        at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.base/java.lang.Thread.run(Thread.java:829)
User avatar
Lapo
Site Admin
Posts: 23438
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: File Upload Issue

Post by Lapo »

Hi,
thanks for reporting.
When Logged In, the IP is 103.119.50.21:60293
But when I tried to upload, it refused the IP 103.119.50.79

Is there any proxy / load-balancer between the client and SFS2X?

Are you sure that the server reported two different addresses during the same test?
Could you try again one more time and confirm that this happens all the times?

Thanks
Lapo
--
gotoAndPlay()
...addicted to flash games
timothyhermawan
Posts: 8
Joined: 10 Dec 2021, 10:47

Re: File Upload Issue

Post by timothyhermawan »

Yes I'm 1000% sure it is the same account and you can also see the time log, I am working on the development server and I am a lone developer, so there's nobody has access to the dev server.

It's 100% reproducible even from my production server and I don't use any proxy or load balancer, there is only one SFS instance.

The same thing happened with my other game that also uses SFS2X, I tried to upload an image and that also threw the same error. it is a brand new server with a fresh Smartfox instance

I also tried to add the actual IP address when the user connected to a zone, set it as a user variable, and add the header to the WebRequest like this but still no luck: (X-Forwarded-For is toggled off in the Admin Tool, but I added it manually)

Code: Select all

 UnityWebRequest request = UnityWebRequest.Post(uploadURL, postForm);
 request.SetRequestHeader("X-Forwarded-For", SmartfoxManager.Instance.sfs.MySelf.GetVariable("ip").GetStringValue());


Do you have any leads?

Thanks
User avatar
Lapo
Site Admin
Posts: 23438
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: File Upload Issue

Post by Lapo »

You did not reply to my other question. Regarding the presence of a reverse-proxy or load-balancer in front of the server? Is there one?
The fact that the HTTP service sees a different address from what SFS2X sees is indicative that something of that kind is going on.

Thanks
Lapo
--
gotoAndPlay()
...addicted to flash games
timothyhermawan
Posts: 8
Joined: 10 Dec 2021, 10:47

Re: File Upload Issue

Post by timothyhermawan »

No, I don't use any proxy or load balancer since I don't set anything related to that, so everything is still the default one.
timothyhermawan
Posts: 8
Joined: 10 Dec 2021, 10:47

Re: File Upload Issue

Post by timothyhermawan »

timothyhermawan wrote:It's 100% reproducible even from my production server and I don't use any proxy or load balancer, there is only one SFS instance.


Actually I already did answer your question tho, but just to make sure, I don't use any proxy or loadbalancer

But I can call the API that I made using the HTTP Request without any issue
User avatar
Lapo
Site Admin
Posts: 23438
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: File Upload Issue

Post by Lapo »

Actually I already did answer your question tho, but just to make sure, I don't use any proxy or loadbalancer

Sorry, my bad.
Still find it pretty weird that the server is reporting a different IP address from the same client. :?
We'll check on our side and get back to you. Can you tell me the version of the Unity client API you're using?

Thanks
Lapo
--
gotoAndPlay()
...addicted to flash games
timothyhermawan
Posts: 8
Joined: 10 Dec 2021, 10:47

Re: File Upload Issue

Post by timothyhermawan »

Since I cannot fix this and have no clue, for a temporary workaround I made the custom API for this
I use org.apache.commons.fileupload package (upload it to SFS2X/lib/apache-tomcat/lib) and create this code to upload the file to the server

Note: I'm still expecting the clue from Smartfox Team

Adjust this for your needs:

Code: Select all

package nomina.slimehaven.servlet.RequestFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.IOUtils;

import com.mongodb.client.ClientSession;
import com.smartfoxserver.v2.SmartFoxServer;
import com.smartfoxserver.v2.extensions.ISFSExtension;

import nomina.slimehaven.CharacterSystem.CharacterManager;
import nomina.slimehaven.Exception.BasicOperationException;
import nomina.slimehaven.SharedClass.GeneralUtility;
import nomina.slimehaven.SharedClass.References.SmartfoxSettings;

public class API_UploadCharacter extends HttpServlet {

   private static final long serialVersionUID = 1L;
   
   static String Destination= "/home/timothyhermawan/SmartFoxServer_2X/SFS2X/www/ROOT/characters/";

   private SmartFoxServer sfs;
    private ISFSExtension myExtension;
   
   @Override
   public void init() throws ServletException
   {
       sfs = SmartFoxServer.getInstance();
       myExtension = sfs.getZoneManager().getZoneByName(SmartfoxSettings.Zone).getExtension();
   }
   
   @Override
   protected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
               
      String uid = request.getHeader("uid");
      String pid = request.getHeader("pid");
      
       // Check if the request is a file upload request
       if (!ServletFileUpload.isMultipartContent(request)) {
          response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            response.getWriter().write("Multipart content expected");
           return;
       }

       // Create a factory for disk-based file items
       FileItemFactory factory = new DiskFileItemFactory();

       // Create a new file upload handler
       ServletFileUpload upload = new ServletFileUpload(factory);

       ClientSession session = GeneralUtility.CreateNewClientSession();
      
       try {              
          CharacterManager.Instance().SetNFTImageCaptured(session, pid, uid);
          
           // Parse the request
           List<FileItem> items = upload.parseRequest(request);
          
           boolean fileFound = false;

           // Process the uploaded items
           for (FileItem item : items) {
              
              if (!item.isFormField() && "theFile".contentEquals(item.getFieldName())) {                  
                 fileFound = true;
                  
                   File uploadedFile = new File(Destination + uid +"/" + item.getName());
                  
                   File parentDir = uploadedFile.getParentFile();
                  
                   if (!parentDir.exists()){
                      parentDir.mkdirs();
                  }
                  
                   InputStream fileContent = item.getInputStream();
                  
                    FileOutputStream outputStream = new FileOutputStream(uploadedFile);
                   
                   IOUtils.copy(fileContent, outputStream);                   
              }
              
            }
            
            if (!fileFound) {
               response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                response.getWriter().write("File field not found");
            }
            else {               
               response.setStatus(HttpServletResponse.SC_OK);
               response.getWriter().write("File uploaded successfully");
               session.commitTransaction();
            }
            
      }
       catch(BasicOperationException e) {
          session.abortTransaction();
          response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
          response.getWriter().write(e.getMessage());
      }
       catch(Exception e) {
          session.abortTransaction();
          response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
          response.getWriter().write(e.getMessage());
      }
      finally {
            session.close();
      }
      
   }
   
   
}


And here is the Unity client code: the uploadURL points to your custom API in Apache Tomcat

Code: Select all

 IEnumerator IEUploadSlime(string uid, Texture2D texture, string uploadURL, Action OnSuccess = null, Action<string> OnFail = null)
 {
     this.texture = texture;

     WWWForm postForm = new WWWForm();
     postForm.AddBinaryData("theFile", texture.EncodeToPNG(), "full-transparent.png", "image/png");

     UnityWebRequest request = UnityWebRequest.Post(uploadURL, postForm);
     request.SetRequestHeader("uid", uid);
     request.SetRequestHeader("pid", AccountInformation.Instance.playerData.pid);

     request.timeout = 10;

     yield return request.SendWebRequest();

     // Check for network errors or HTTP errors
     if (request.result == UnityWebRequest.Result.ConnectionError || request.result == UnityWebRequest.Result.ProtocolError)
     {
         OnFail?.Invoke($"Error: {request.error}\nMessage: {request.downloadHandler.text}");
     }
     else
     {
         OnSuccess?.Invoke();
     }
 }
timothyhermawan
Posts: 8
Joined: 10 Dec 2021, 10:47

Re: File Upload Issue

Post by timothyhermawan »

Lapo wrote:
Actually I already did answer your question tho, but just to make sure, I don't use any proxy or loadbalancer

Sorry, my bad.
Still find it pretty weird that the server is reporting a different IP address from the same client. :?
We'll check on our side and get back to you. Can you tell me the version of the Unity client API you're using?

Thanks



My Unity Client API version is: 1.7.15
User avatar
Lapo
Site Admin
Posts: 23438
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: File Upload Issue

Post by Lapo »

We have tested the upload scenario using the latest SFS2X and latest Unity Client API (version 1.8.3)
On the client side we use the snippet provided in our documentation --> https://docs2x.smartfoxserver.com/Advan ... le-uploads

And it works as expected, no errors. So I am not sure where the problem could be other than in your setup.
Can you reproduce the issue on your local machine as well? Even with the different client IP addresses?

Cheers
Lapo
--
gotoAndPlay()
...addicted to flash games
Post Reply