How to serve a pre-compressed data with actix-web?


#1

Hi crustaceans,

I have to serve a data field from database, that field is already compressed in ‘gzip’. So, the response must have "Content-type":"application/x-protobuf", and "Content-Encoding":"gzip". Previously, I successfully serve them with Iron. Now, I am in the process of migrating the server app to actix-web. But Actix automatically compresses/decompresses payloads: If I set "Content-Encoding":"gzip", actix-web will compress it… again!!! ???

How can I disable the compression and set "Content-Encoding":"gzip"? Or I should file an issue on actix-web repo?


#2

@fafhrd91 comes around this way here and there - he’ll know :slight_smile:


#3

@limira you have two options:

  • you need to use ContentEncoding::Identity

        HttpResponse::().content_encoding(ContentEncoding::Identity)
    
  • Or you can set default encoding on application level with App::default_encoding()

@vitalyd thanks


#4

What I tried:

  1. Decompress :neutral_face:: (works as expected)

     let data = decompress(data); // decompress from gzip
     let res = HttpResponse::Ok()
         .content_type("application/x-protobuf")
         .content_encoding(ContentEncoding::Gzip)
         .body(data);
     Ok(res)
    
  2. Serve the data as is with ContentEncoding::Identity (does not work…)

     //let data = decompress(data); // this line was removed
     let res = HttpResponse::Ok()
         .content_type("application/x-protobuf")
         .content_encoding(ContentEncoding::Identity)
         .body(data);
     Ok(res)
    

I did not try with App::default_encoding, I think it is the same with case 2 above.


#5

@fafhrd91, I think you might ignored my latest reply (aboved), because there is a “(works as expected)” phrase appear in my post. Actually, the case number 1 (Decompress) works, but it is not what I want and it is unreasonable.

Here is case 1 (again, with more detail)

let data: Vec<u8> = ...;// a value which is already in gzip, that is load from database

let data = decompress(data); // <========== decompress from gzip

let res = HttpResponse::Ok()
    .content_type("application/x-protobuf")
    .content_encoding(ContentEncoding::Gzip) // <============= compress back to gzip
    .body(data);
Ok(res)

It is unreasonable to decompress a gzip-value, just then tell actix to compress it again in the same format. What I want is to serve the data as is, but using ContentEncoding::Identity as your suggestion does not work (I mean the client app in the browser does not understand the received value). Here is the code using ContentEncoding::Identity:

let data: Vec<u8> = ...;// a value which is already in gzip, that is load from database
let res = HttpResponse::Ok()
     .content_type("application/x-protobuf")
     .content_encoding(ContentEncoding::Identity)
     .body(data);
Ok(res)

#6

@limira

I agree, decompression should not be required. did you try to add content-encoding header?

let res = HttpResponse::Ok()
     .header("content-encoding", "gzip")
     .content_type("application/x-protobuf")
     .content_encoding(ContentEncoding::Identity)
     .body(data);
 Ok(res)

#7

Thank you for your help!

Actually, I did try .content_encoding(ContentEncoding::Gzip), and it does not work. Now with your sugguestion: .header("content-encoding", "gzip"), it works. So they are different ways to do the same (?) thing with different effects.

Here is the solution for anyone who need it:

let res = HttpResponse::Ok()
    .content_type("application/x-protobuf")
    //.content_encoding(ContentEncoding::Gzip) // <======= this does not work
    .header("content-encoding", "gzip")  // <======== this works
    .content_encoding(ContentEncoding::Identity)
    .body(data);
Ok(res)

Thanks again!


#8

if you use “ContentEncoding::Identity” then actix does not modify response, and it is your responsibility to set proper headers and body