Skip to content
This repository has been archived by the owner on Jan 21, 2020. It is now read-only.

File uploading with PUT method with Method Override #89

Open
Channad opened this issue Oct 2, 2017 · 9 comments
Open

File uploading with PUT method with Method Override #89

Channad opened this issue Oct 2, 2017 · 9 comments
Assignees
Labels

Comments

@Channad
Copy link

Channad commented Oct 2, 2017

I am trying to upload a file in a form with other data fields provided via Angular 4. With lot of difficulty I managed to get it posting properly. It requires that I remove the Content-Type header from the ajax posting.

So now both POST and PUT works as normally. However I have encountered a problem with apigility behavior when it comes to X-HTTP-Method-Override header. The POST method still works fine but PUT fails on input validation. Apigility reports all my required fields as empty when actually they are not.

As I said this happens only when I use POST with Method Overriding to PUT.

Also noticed that allow_empty and continue_if_empty does not work.

My production server does not support PUT & DELETE methods. So I need to get this working.

My module.config.php has the following for the specific file upload field:

6 => [
    'name' => 'projProposal',
    'required' => false,
    'filters' => [
        0 => [
            'name' => \Zend\Filter\File\RenameUpload::class,
            'options' => [
                'target' => 'data/uploads/projects/',
                'use_upload_extension' => true,
                'randomize' => true,
            ],
        ],
    ],
    'validators' => [
        0 => [
            'name' => \Zend\Validator\File\MimeType::class,
            'options' => [
                'mimeType' => 'pdf,doc,docx,xls,xlsx,application/vnd.openxmlformats-officedocument.wordprocessingml.document,enxmlformats-officedocument.spreadsheetml.sheet',
            ],
        ],
        1 => [
            'name' => \Zend\Validator\File\Size::class,
            'options' => [
                'max' => '10485760',
            ],
        ],
    ],
    'type' => \Zend\InputFilter\FileInput::class,
    'allow_empty' => false,
    'continue_if_empty' => true,
    'error_message' => 'Upload Failed.....',
],

My Template has the following among others:

<form (ngSubmit)="onSubmit(dataRecord)" #entryForm="ngForm">
  <div class="form-group " *ngIf="(action !== 'View') || (action !== 'Delete')">
    <label for="projProposal">Upload project proposal</label> 
    <input type="file"
      class="form-control" id="projProposal"
      title="Upload files of type .pdf,.doc,.docx" 
accept=".pdf,.doc,.docx"
      name="projProposal"
      minlength="1"
      maxlength="500"
      size="5em"
      [readonly]="(action === 'View') || (action === 'Delete')">
    <div *ngIf="formErrors.projProposal" class="alert alert-danger">{{
      formErrors.projProposal }}</div>
  </div>
</form>

My data service has the following:

editRecord (data: any): Observable<Response> {
  let url = this._url + '/' + data.get('projectId');
  const headers = new Headers({ 'Accept': '*/*',
    'X-HTTP-Method-Override': 'PUT', // Not required if the server support PUT method
    'Authorization': (this.authService.authresponse.token_type + ' ' + this.authService.getToken())
  });
  const options = new RequestOptions({ headers: headers});
  return this.http.post(url, data, options)
                  .map(this.extractData)
                  .catch(this.handleError);
}

The Response I get is:

{
  "validation_messages": {
    "projDesc": {
      "isEmpty": "Value is required and can't be empty"
    },
    "projCategory": {
        "isEmpty":"Value is required and can't be empty"
    },
    "projStart": {
      "isEmpty":"Value is required and can't be empty"
    },
    "projEnd": {
      "isEmpty": "Value is required and can't be empty"
    },
    "createdOn": {
      "isEmpty": "Value is required and can't be empty"
    },
    "createdBy": {
      "isEmpty": "Value is required and can't be empty"
    }
  },
  "type": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html",
  "title":"Unprocessable Entity",
  "status":422,
  "detail":"Failed Validation"
}

My Browser says this

Accept:*/*
Accept-Encoding:gzip, deflate
Accept-Language:en-GB,en-US;q=0.8,en;q=0.6
Authorization:Bearer 4ef85a6aea3bdfd5e9a19bd28df145254c6e8133
Connection:keep-alive
Content-Length:73442
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryAPvdSnxwn6DQnYdP
Host:192.168.2.21
Origin:http://localhost:4200
Referer:http://localhost:4200/projectDefinitions/edit/4;mode=Edit;showPage=1;showRows=11;filters=%7B%7D
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36
X-HTTP-Method-Override:PUT

------WebKitFormBoundaryAPvdSnxwn6DQnYdP
Content-Disposition: form-data; name="projectId"

4
------WebKitFormBoundaryAPvdSnxwn6DQnYdP
Content-Disposition: form-data; name="projDesc"

Sapiri Gevathu
------WebKitFormBoundaryAPvdSnxwn6DQnYdP
Content-Disposition: form-data; name="projCategory"

3002
------WebKitFormBoundaryAPvdSnxwn6DQnYdP
Content-Disposition: form-data; name="projStart"

2017-01-01
------WebKitFormBoundaryAPvdSnxwn6DQnYdP
Content-Disposition: form-data; name="projEnd"

2017-12-30
------WebKitFormBoundaryAPvdSnxwn6DQnYdP
Content-Disposition: form-data; name="applSeason"

1
------WebKitFormBoundaryAPvdSnxwn6DQnYdP
Content-Disposition: form-data; name="projObjectives"

Objective Two
------WebKitFormBoundaryAPvdSnxwn6DQnYdP
Content-Disposition: form-data; name="projProposal"; filename="AGREEMENT-new.pdf"
Content-Type: application/pdf


------WebKitFormBoundaryAPvdSnxwn6DQnYdP
Content-Disposition: form-data; name="createdOn"

2017-09-29 08:48:31
------WebKitFormBoundaryAPvdSnxwn6DQnYdP
Content-Disposition: form-data; name="createdBy"

user
------WebKitFormBoundaryAPvdSnxwn6DQnYdP
Content-Disposition: form-data; name="modifiedOn"

2017-10-2 8:2:22
------WebKitFormBoundaryAPvdSnxwn6DQnYdP
Content-Disposition: form-data; name="modifiedBy"

user
------WebKitFormBoundaryAPvdSnxwn6DQnYdP--
@ezimuel ezimuel self-assigned this Oct 2, 2017
@ezimuel
Copy link
Contributor

ezimuel commented Oct 2, 2017

@Channad I think the issue comes because the ContentTypeListener is executed before the HttpMethodOverrideListener. Can you try to change the priority to -1000 (instead of -40 here) and let me know if this solve the problem?
I'm trying to reproduce the issue with unit test but it will require some times. If you can check this will simplify the debugging. Thanks!

@weierophinney
Copy link
Member

@Channad Also... The Angular 4 HttpClient (https://angular.io/api/common/http/HttpClient) provides methods for HTTP methods other than GET and POST - it also supports HEAD, PATCH, PUT, and DELETE. As such, you may not even need to use the X-HTTP-Method-Override header at all, which could solve the problem.

@Channad
Copy link
Author

Channad commented Oct 2, 2017

Mathewe As I mentioned the need for the Method Override is due to the restrictions on the SSL based commercial server which does not allow PUT and DELETE and even OPTION is not allowed.

@Channad
Copy link
Author

Channad commented Oct 2, 2017

@ezimuel ,

Thanks Enrico the -1000 did the trick, it resolved the problem. Also in my issue I also mentioned that the Allow Empty and Continue_if_empty flags are not working. It always asks for the file to be present

@Channad Channad closed this as completed Oct 3, 2017
@Channad
Copy link
Author

Channad commented Oct 3, 2017

@ezimuel

Sorry I accidentally closed the issue.

Well the priority setting fixed the PUT issues on file upload but it breaks every thing else. All other methods fail such as POST, DELETE and PUT methods on application/json fails.

they work ok with a priority setting of -100, but then the multipart/form-data fails.

What am I to do to fix this???

Can I override the HttpMethodOverrideListner class and set the priority for those tables which needs multipart/form-data?

@Channad Channad reopened this Oct 3, 2017
@ezimuel
Copy link
Contributor

ezimuel commented Oct 3, 2017

@Channad ok, I need to test it properly. It will require some times since I need to provide a full unit test to debug it. I'll let you know asap.

@Channad
Copy link
Author

Channad commented Oct 3, 2017

@ezimuel

Hi Enrico,

Few more updates from my side I think may help you to help all of us.

At priority level –1000 the system works without a problem if I have the
POST method enabled on all my other table services at entity level.

At present I have not enabled POST method on tables which has a auto generated ID. Auto ID tables have POST method only at collection level.

All tables with composite keys have POST method enabled at entity level and no POST at collection level, Which is fine for a relational table structure. Everything works fine with these table REST service with priority at -1000.

The Issue is with those tables which has POST only enabled at collection level where the primary key is auto generated. Obviously we cant have POST at entity level as the primary key value is unknown to submit a post request. For these tables if I add the POST method It seems to work fine with the Method Override and priority -1000. But I am sure it will fail without Method Override.

So the issue seems to be that Overriding Listener is intercepting the "Allowed Methods" validation listener at priority level -1000.

Hope this will help your debugging process!

Best regards
Channa

@Channad
Copy link
Author

Channad commented Oct 4, 2017

@ezimuel
Hi Enrico,

RE Allow_Empty and continue_if_empty flags, it looks like the system does not check what the value of the flags are but just if the flags are there or not.

If I need to allow empty on the file upload, I should remove the allow_empty and continue_if_empty flags from the module.config.php

Best regards
Channa

@weierophinney
Copy link
Member

This repository has been closed and moved to laminas-api-tools/api-tools-content-negotiation; a new issue has been opened at laminas-api-tools/api-tools-content-negotiation#4.

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

No branches or pull requests

3 participants