Skip to content

Unable to upload files (images) #3615

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
PunkStarStudios opened this issue Mar 10, 2017 · 4 comments
Closed

Unable to upload files (images) #3615

PunkStarStudios opened this issue Mar 10, 2017 · 4 comments

Comments

@PunkStarStudios
Copy link

Issue Description

Since moving to my own server (from parse.com), I am unable to upload images/files of any size. Downloading files/images and updating/fetching data works fine.

The only issues that seem to match mine refer to file sizes being large with a fix bing to update nginx.conf (as well as the server and location contexts in the relevant site config files) to have the setting :
client_max_body_size 100m;

This fix has not worked for me - I've tried uploading files as small as 2mb with no luck.

I have tried to upload images as part of an array in one object (where an array is expected), as well as a simply one off file in another object (where no array is expected).
An error happens with both cases.

Steps to reproduce

Please include a detailed list of steps that reproduce the issue. Include curl commands when applicable.

In my macOS application I initialize Parse as so:
[Parse initializeWithConfiguration:[ParseClientConfiguration configurationWithBlock:^(id configuration) {
configuration.applicationId = @"myappid";
configuration.clientKey = @"myClientKey";
configuration.server = @"https://myservername.com/parse/";
}]];

I am able to retrieve and update records normally.... both through macOS app and restFUL via linux box.

I attempt to upload an image using :

.
//openDlg is a file dialog box that allows the user to select the file. I've omitted the code for simplicity here.
NSString *filePath = [[openDlg URL] path];
PFFile *theImage = [PFFile fileWithName:filename contentsAtPath:filePath];
//set various fields
newFlyerObject[@"clientObjectId"] = @"test";
newFlyerObject[@"locationObjectId"] = @"test";
//set the image
newFlyerObject[@"image"] = theImage;

[newFlyerObject saveInBackgroundWithBlock:^(BOOL succeeded, NSError error) {
if(error){
NSLog(@"
** Error saving new flyer (%@) %@",error,error.userInfo);
} else {
//Everything was saved
[self.dataFlyers addObject:objectToSave];
[self.tableFlyerList reloadData];
}
[self changeLevelValue:-1 eventDescription:@"LoadFlyerFromDisc (A)"];
}];

Expected Results

File and values saved to the database.

Actual Outcome

Nothing is saved and the error is :
*** Error saving new flyer (Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}) {
NSDebugDescription = "JSON text did not start with array or object and option to allow fragments not set.";
}

If I remove the line newFlyerObject[@"image"] = theImage;
The object is saved fine (albeit with no image data).

Environment Setup

Installed parse-server-example followed by the required NPMs:
express
mongoldb-runner
parse-server
parse-server-fs-adapter

  • Server

    • parse example server version : 2.15.9
    • parse-server version : 2.3.6
    • parse-server-fs-adapter version : 1.0.1
    • Operating System: Ubuntu 14.04.5 LTS
    • Hardware: ASUSTeK rack server X86_64, P9D-M Series
    • Localhost or remote server? (AWS, Heroku, Azure, Digital Ocean, etc): Local
  • Database

    • MongoDB version: 3.0.14
    • Storage engine: Storage Engine? Mongo is locally installed.
    • Hardware: ASUSTeK rack server X86_64, P9D-M Series
    • Localhost or remote server? (AWS, mLab, ObjectRocket, Digital Ocean, etc): Local

Logs/Trace

Include all relevant logs. You can turn on additional logging by configuring VERBOSE=1 in your environment.
I cleaned out the logs and ran the code.
NO log files located in /var/www/parse/logs
NO log files located in /var/log/nginx

@PunkStarStudios
Copy link
Author

PunkStarStudios commented Mar 10, 2017

I have an interesting update.....
Tried using restFUL....

curl -X POST
-H "X-Parse-Application-Id: myappid"
-H "X-Parse-REST-API-Key: myrestkey"
-H "Content-Type: image/jpg"
--data-binary '@1.jpg'
https://myserver.com/parse/files/1.jpg

Results in an error.

404 Not Found
nginx/1.10.1
(html tags removed)

but

curl -X POST
-H "X-Parse-Application-Id: myappid"
-H "X-Parse-REST-API-Key: myrestkey"
-H "Content-Type: image/jpg"
--data-binary '@1.jpg'
http://myserver.com:1337/parse/files/1.jpg

does not result in an error.
Huh.
Unfortunately - connecting to the parse server via http isn't an option - OSX balks at it.

I can however retrieve a file via both HTTP and HTTPS.

@PunkStarStudios
Copy link
Author

PunkStarStudios commented Mar 10, 2017

Some more troubleshooting...
I took that parse-server-fs-fileadapter thing out of the parse instance (index.js).
restarted parse after stopping it (npm start)

Files still get served.

But I noticed that CURL posting a file via HTTPS still does not work. And posting it via HTTP does - it reports back that it was put into a specific directory (/var/www/parse/files/appid/xxxx.jpg).
But it doesn't actually exist there - it does exist in mongo's fs.files ... which I assume is it's GridStore thing that is built in.

By dumb luck - I happened to setup a directory that matches what's found in the FileRouter.js file (/node_modules/parse-server/lib/Routers) - so things are MOSTLY working... but not 100%.
I'd abandon the FS router if I could (if I had some way to move all those files into gridstore), but then I'd still be left with the problem that I can't upload files via https.

@PunkStarStudios
Copy link
Author

PunkStarStudios commented Mar 13, 2017

Ok - so I quasi have this figured out.
It's probably an NGINX sites file configuration causing me grief ... but... well.. the thing is I thought the filerouter.js would do something that it isn't doing.

I have parse server installed under
/var/www/parse

I have a whole slew of files stored under
/var/www/parse/files/appid/

If in my HTTPS section of the NGINX file (/etc/nginx/sites-enabled/default) I have this ...
location /parse/files {
root /var/www;
autoindex on; //Just in there for debugging purposes
}

I get those files no problem. Parse API calls give me an url like myserver/parse/files/appid/filename.jps
And I can get that file no problem via browser or in code via http or https
But I can't upload via HTTPS (just http)

However.
If I get rid of that location /parse/files section I can upload and download via HTTP or HTTPS and it goes into the mongo gridstore.
However - I am not able to access the physical files residing on /var/www/parse/files/appid/

I thought filerouter.js did some fancy routing to send you to that directory should it not be found in grid store.... but perhaps I am wrong.

Can anyone suggest how parse server can default to to that physical directory should the actual file not be found in the gridstore mongo table?

@PunkStarStudios
Copy link
Author

SCORE.
Well I figured it out... and I'm posting some tips here for future hair-puller-outters.

This is what I had to do to fix my problem. First off - I am not using grid store... Gridstore does work just fine if you start out fresh but if you have a few thousand images stored in a folder and not in gridstore - I have not figured out a way to push all those into mongo.gridstore and retain links to existing entries...

Anyhow... first I am using parse-server-fs-adapter
So in my index.js file I have
var FileAdapter = require('parse-server-fs-adapter');
...
var api = new ParseServer({
...
filesAdapter: new FileAdapter({
filesSubDirectory: './myAppID'
})
});

Secondly - for my /etc/nginx/sites-enabled/default file (no I won't go into details on obtaining an SSL certificate and all that here)....

server {
listen 80;
server_name myserver.com;
client_max_body_size 100m;

    location /parse/ {
            root /var/www;

useful for debugging otherwise turn off to "hide" files

autoindex on;

    }

    error_log /etc/nginx/logs/80.txt debug;

}

HTTPS - serve HTML from /usr/share/nginx/html, proxy requests to /parse/

through to Parse Server

server {
listen 443;
client_max_body_size 100m;

    server_name myserver.com;
    error_log /etc/nginx/logs/443.txt debug;

    ssl on;
    # Use certificate and key provided by Let's Encrypt:
    ssl_certificate /etc/letsencrypt/live/myserver.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/myserver.com/privkey.pem;
    ssl_session_timeout 5m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
    # Pass requests for /parse/ to Parse Server instance at localhost:1337
    location /parse/ {
            root /var/www;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header X-NginX-Proxy true;
            proxy_pass http://localhost:1337;
            proxy_ssl_session_reuse off;
            proxy_set_header Host $http_host;
            proxy_redirect off;
            #WebSocket support
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
    }

    location ~ /.well-known {
            allow all;
    }

}

Parse is installed under
/var/www/parse

The physical files are stores under
/var/www/parse/files/myappid/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant