Readable debug logging for http requests with spring webclient - spring

I'm using Spring reactive WebClient for sending requests to a http server. Inorder to view the underlying request & response that's being sent, I enabled debug logging for reactor.ipc.netty package.
The headers for the outgoing requests can be viewed normally.
Tho I'm sending & receiving plain text over http, the log contains the request & responses in the below format (is it hex?)
I'm not sure how to view the logged data in a easy to understand way. Better yet log the request & response in a understandable way
Here is a snippet of the logged data
+-------------------------------------------------+
| 0 1 2 3 4 5 6 7 8 9 a b c d e f |
+--------+-------------------------------------------------+----------------+
|00000000| 47 45 54 20 2f 53 65 61 72 63 68 5f 47 43 2e 61 |GET /Search_GC.a|
|00000010| 73 70 78 20 48 54 54 50 2f 31 2e 31 0d 0a 75 73 |spx HTTP/1.1..us|
|00000020| 65 72 2d 61 67 65 6e 74 3a 20 52 65 61 63 74 6f |er-agent: Reacto|
|00000030| 72 4e 65 74 74 79 2f 30 2e 37 2e 32 2e 52 45 4c |rNetty/0.7.2.REL|
|00000040| 45 41 53 45 0d 0a 68 6f 73 74 3a 20 63 65 6f 6b |EASE..host: ceok|
|00000050| 61 72 6e 61 74 61 6b 61 2e 6b 61 72 2e 6e 69 63 |arnataka.kar.nic|
|00000060| 2e 69 6e 0d 0a 61 63 63 65 70 74 3a 20 2a 2f 2a |.in..accept: */*|
|00000070| 0d 0a 61 63 63 65 70 74 2d 65 6e 63 6f 64 69 6e |..accept-encodin|
|00000080| 67 3a 20 67 7a 69 70 0d 0a 63 6f 6e 74 65 6e 74 |g: gzip..content|
|00000090| 2d 6c 65 6e 67 74 68 3a 20 30 0d 0a 0d 0a |-length: 0.... |
+--------+-------------------------------------------------+----------------+
Found an unanswered question that must be happening because of the same library: Reading a HttpContent that has a PooledUnsafeDirectByteBuf
Raised an issue here
There seems to an orthodox view that debugging is not required for reactive clients. This is a completely pointless arguments as we use tools like rest client, postman, curl, httpie & others to send request and view response

They changed the reactor.netty.http.client.HttpClient class, after I upgraded to io.projectreactor.netty:reactor-netty-http:1.0.5 the following code is compilable and does what you expect. (I am not sure which is the minimal version, I upgraded from something older, but I guess it's 1.0.0. It is a transitive dependency, I upgraded spring-boot-starter-webflux from 2.3.4.RELEASE to 2.4.4.)
The crucial part is the call of wiretap():
wiretap("reactor.netty.http.client.HttpClient", LogLevel.DEBUG, AdvancedByteBufFormat.TEXTUAL, StandardCharsets.UTF_8)
It logs also the header and body of the request and of the response.
The whole context is this:
package com.example;
import io.netty.handler.logging.LogLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import reactor.netty.http.client.HttpClient;
import reactor.netty.transport.logging.AdvancedByteBufFormat;
import java.nio.charset.StandardCharsets;
#Slf4j
class RestClientTest {
private WebClient createWebClient() {
final HttpClient httpClient = HttpClient.create()
.wiretap(HttpClient.class.getCanonicalName(), LogLevel.DEBUG, AdvancedByteBufFormat.TEXTUAL, StandardCharsets.UTF_8);
return WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
}
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
private static class User {
int id;
int userId;
String title;
String body;
}
#Test
void createUsersReactive() {
final WebClient webClient = createWebClient();
final String url = "http://jsonplaceholder.typicode.com/posts";
final Mono<User> userMono = webClient.method(HttpMethod.POST)
.uri(url)
.contentType(MediaType.APPLICATION_JSON_UTF8)
.header("X-My-Header", "MyValue1", "MyValue2")
.body(BodyInserters.fromValue(User.builder().userId(1).title("foo").body("bar").build()))
.retrieve()
.bodyToMono(User.class);
final User user = userMono.block();
log.info("Created user: " + user);
}
}
And the output to log is human readable as you request:
... reactor.netty.http.client.HttpClient : [id:e7d7ed93] REGISTERED
... reactor.netty.http.client.HttpClient : [id:e7d7ed93] CONNECT: jsonplaceholder.typicode.com/<unresolved>:80
... reactor.netty.http.client.HttpClient : [id:e7d7ed93] ACTIVE
... r.netty.http.client.HttpClientConnect : [id:e7d7ed93-1] Handler is being applied: {uri=http://jsonplaceholder.typicode.com/posts, method=POST}
... reactor.netty.http.client.HttpClient : [id:e7d7ed93-1] WRITE: 217B POST /posts HTTP/1.1
user-agent: ReactorNetty/1.0.5
host: jsonplaceholder.typicode.com
accept: */*
Content-Type: application/json;charset=UTF-8
X-My-Header: MyValue1
X-My-Header: MyValue2
content-length: 46
... reactor.netty.http.client.HttpClient : [id:e7d7ed93-1] WRITE: 46B {"id":0,"userId":1,"title":"foo","body":"bar"}
... reactor.netty.http.client.HttpClient : [id:e7d7ed93-1] FLUSH
... reactor.netty.http.client.HttpClient : [id:e7d7ed93-1] READ: 1347B HTTP/1.1 201 Created
Date: Tue, 13 Apr 2021 12:49:33 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 65
X-Powered-By: Express
X-Ratelimit-Limit: 1000
X-Ratelimit-Remaining: 999
X-Ratelimit-Reset: 1618318233
Vary: Origin, X-HTTP-Method-Override, Accept-Encoding
Access-Control-Allow-Credentials: true
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Access-Control-Expose-Headers: Location
Location: http://jsonplaceholder.typicode.com/posts/101
X-Content-Type-Options: nosniff
Etag: W/"41-0LtsWqhuQ7Zsjlj0tYnOrT/Vw5o"
Via: 1.1 vegur
CF-Cache-Status: DYNAMIC
cf-request-id: 096ce0bd560000736722853000000001
Report-To: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report?s=laAKjgGcoi8SLu%2F6VX5pQIAksdmj9xi31elC5Ld97eljznKIpYjdkQsittoMJp3lJoQIwOACmj89bKSa%2Ff15gRHRmyasV2Xcl%2FmVjJBJm7ytbWocp39UBd90JwVM"}],"max_age":604800,"group":"cf-nel"}
NEL: {"max_age":604800,"report_to":"cf-nel"}
Server: cloudflare
CF-RAY: 63f4d0a88ed07367-CPH
alt-svc: h3-27=":443"; ma=86400, h3-28=":443"; ma=86400, h3-29=":443"; ma=86400
Proxy-Connection: Keep-Alive
Connection: Keep-Alive
Set-Cookie: __cfduid=d11c86fbd953f7cf768cf7db0c346f22b1618318173; expires=Thu, 13-May-21 12:49:33 GMT; path=/; domain=.typicode.com; HttpOnly; SameSite=Lax
{
"id": 101,
"userId": 1,
"title": "foo",
"body": "bar"
}
... r.n.http.client.HttpClientOperations : [id:e7d7ed93-1] Received response (auto-read:false) : [Date=Tue, 13 Apr 2021 12:49:33 GMT, Content-Type=application/json; charset=utf-8, X-Powered-By=Express, X-Ratelimit-Limit=1000, X-Ratelimit-Remaining=999, X-Ratelimit-Reset=1618318233, Vary=Origin, X-HTTP-Method-Override, Accept-Encoding, Access-Control-Allow-Credentials=true, Cache-Control=no-cache, Pragma=no-cache, Expires=-1, Access-Control-Expose-Headers=Location, Location=http://jsonplaceholder.typicode.com/posts/101, X-Content-Type-Options=nosniff, Etag=W/"41-0LtsWqhuQ7Zsjlj0tYnOrT/Vw5o", Via=1.1 vegur, CF-Cache-Status=DYNAMIC, cf-request-id=096ce0bd560000736722853000000001, Report-To={"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report?s=laAKjgGcoi8SLu%2F6VX5pQIAksdmj9xi31elC5Ld97eljznKIpYjdkQsittoMJp3lJoQIwOACmj89bKSa%2Ff15gRHRmyasV2Xcl%2FmVjJBJm7ytbWocp39UBd90JwVM"}],"max_age":604800,"group":"cf-nel"}, NEL={"max_age":604800,"report_to":"cf-nel"}, Server=cloudflare, CF-RAY=63f4d0a88ed07367-CPH, alt-svc=h3-27=":443"; ma=86400, h3-28=":443"; ma=86400, h3-29=":443"; ma=86400, Proxy-Connection=Keep-Alive, Connection=Keep-Alive, Set-Cookie=__cfduid=d11c86fbd953f7cf768cf7db0c346f22b1618318173; expires=Thu, 13-May-21 12:49:33 GMT; path=/; domain=.typicode.com; HttpOnly; SameSite=Lax, content-length=65]
... r.n.http.client.HttpClientOperations : [id:e7d7ed93-1] Received last HTTP packet
... reactor.netty.http.client.HttpClient : [id:e7d7ed93] READ COMPLETE
... com.example.RestClientTest : Created user: RestClientIT.User(id=101, userId=1, title=foo, body=bar)

You can do it with doOnNext(), if you use DataBuffer as your reader:
public Mono<ServerResponse> selectByPost(ServerRequest request) {
Flux<DataBuffer> requestBodyFlux = request.bodyToFlux(DataBuffer.class)
.doOnNext(dataBuffer -> {
if (debug ) {
log.debug(new String(dataBuffer.asByteBuffer().array()));
}
Scannable.from(dataBuffer).tags().forEach(System.out::println);
});
}
This is probably not the best way to do it, it would of course be a nice feature, if netty would provide different ways of logging the payload. Hex does have its benefits, depending on what you need to debug.

Seems like the responding server is returning gzipped content, so it makes sense that you're not able to read it.
If you really want to intercept at the raw HTTP level, ensure your request header does not specify it can accept GZipped content (accept-encoding: gzip).
Another alternative may be to log the request at another layer, when it's already been unzipped from the raw data stream, but not yet processed by your application code - not sure how this would work in Reactive webclient though ;)

Related

How to send delete request with custom header using Spring's WebClient?

I want to send an http delete request with custom header.
I tried to do this with Spring's WebClient, with following code:
#Test
public void validateDeleteCouldCarryHeader() {
WebClient.create("https://jira.spring.io/")
.delete()
.header("X-FOO", "BAR")
.retrieve()
.bodyToMono(Map.class)
.block();
}
I am expecting something like:
DELETE / HTTP/1.1
X-FOO: BAR
...
content-length: 0
But, the actual request made is:
DELETE / HTTP/1.1
user-agent: ReactorNetty/0.7.0.RELEASE
host: jira.spring.io
accept: */*
accept-encoding: gzip
content-length: 0
Did I miss some thing to include the custom header X-FOO ?
Update 1: I upgraded reactor-netty to 0.7.3.RELEASE,
And the missing header is still missing:
DELETE / HTTP/1.1
user-agent: ReactorNetty/0.7.3.RELEASE
host: jira.spring.io
accept: */*
accept-encoding: gzip
content-length: 0
2018-12-28 22:32:32.813 DEBUG 12064 --- [ctor-http-nio-4] r.ipc.netty.http.client.HttpClient : [id: 0x2c6a9cea, L:/172.17.1.131:54532 - R:jira.spring.io/35.199.60.33:443] WRITE: 138B
+-------------------------------------------------+
| 0 1 2 3 4 5 6 7 8 9 a b c d e f |
+--------+-------------------------------------------------+----------------+
|00000000| 44 45 4c 45 54 45 20 2f 20 48 54 54 50 2f 31 2e |DELETE / HTTP/1.|
|00000010| 31 0d 0a 75 73 65 72 2d 61 67 65 6e 74 3a 20 52 |1..user-agent: R|
|00000020| 65 61 63 74 6f 72 4e 65 74 74 79 2f 30 2e 37 2e |eactorNetty/0.7.|
|00000030| 33 2e 52 45 4c 45 41 53 45 0d 0a 68 6f 73 74 3a |3.RELEASE..host:|
|00000040| 20 6a 69 72 61 2e 73 70 72 69 6e 67 2e 69 6f 0d | jira.spring.io.|
|00000050| 0a 61 63 63 65 70 74 3a 20 2a 2f 2a 0d 0a 61 63 |.accept: */*..ac|
|00000060| 63 65 70 74 2d 65 6e 63 6f 64 69 6e 67 3a 20 67 |cept-encoding: g|
|00000070| 7a 69 70 0d 0a 63 6f 6e 74 65 6e 74 2d 6c 65 6e |zip..content-len|
|00000080| 67 74 68 3a 20 30 0d 0a 0d 0a |gth: 0.... |
+--------+-------------------------------------------------+----------------+
Update 2: I found there's a reactor's BOM (Bismuth-RELEASE) imported in my pom, after removed that BOM, Spring Boot 2.0.5.RELEASE included the custom header I want.
DELETE / HTTP/1.1
user-agent: ReactorNetty/0.7.9.RELEASE
host: jira.spring.io
accept: */*
accept-encoding: gzip
X-FOO: BAR
Reactor Netty 0.7.0.RELEASE is quite old now, and you should upgrade to a newer version.
I've tried to reproduce this and couldn't.
Setting the log level of reactor.ipc.netty.http.client.HttpClient to "DEBUG" shows this:
[reactor-http-nio-4] DEBUG reactor.ipc.netty.http.client.HttpClient - [id: 0x69202b84, L:/192.168.0.28:60880 - R:jira.spring.io/35.199.60.33:443] WRITE: 150B
+-------------------------------------------------+
| 0 1 2 3 4 5 6 7 8 9 a b c d e f |
+--------+-------------------------------------------------+----------------+
|00000000| 44 45 4c 45 54 45 20 2f 20 48 54 54 50 2f 31 2e |DELETE / HTTP/1.|
|00000010| 31 0d 0a 75 73 65 72 2d 61 67 65 6e 74 3a 20 52 |1..user-agent: R|
|00000020| 65 61 63 74 6f 72 4e 65 74 74 79 2f 30 2e 37 2e |eactorNetty/0.7.|
|00000030| 30 2e 52 45 4c 45 41 53 45 0d 0a 68 6f 73 74 3a |0.RELEASE..host:|
|00000040| 20 6a 69 72 61 2e 73 70 72 69 6e 67 2e 69 6f 0d | jira.spring.io.|
|00000050| 0a 61 63 63 65 70 74 3a 20 2a 2f 2a 0d 0a 61 63 |.accept: */*..ac|
|00000060| 63 65 70 74 2d 65 6e 63 6f 64 69 6e 67 3a 20 67 |cept-encoding: g|
|00000070| 7a 69 70 0d 0a 58 2d 46 4f 4f 3a 20 42 41 52 0d |zip..X-FOO: BAR.|
|00000080| 0a 63 6f 6e 74 65 6e 74 2d 6c 65 6e 67 74 68 3a |.content-length:|
|00000090| 20 30 0d 0a 0d 0a | 0.... |
+--------+-------------------------------------------------+----------------+
So the client is indeed sending those headers. Maybe there's something wrong with the way you're capturing the outgoing request information?

Websocket client hanshake error 426 on upgrade

Reader's digest version:
First time writing a websocket client. Java 1.8 using Eclipse. While on my workplace internal network getting a handshake error exception and the websocket log information tells me:
< Session 1c61123c-aa5f-4e59-a49d-b5d3c77c0bbd [598 ms]: Received handshake response:
< 426
< connection: Keep-Alive
< content-length: 29
< content-type: text/plain; charset=utf-8
< date: Mon, 12 Jun 2017 16:40:04 GMT
< server: nginx
Exception in thread "main" java.lang.RuntimeException: javax.websocket.DeploymentException: Handshake error.
at webSocketExample.WebsocketClientEndpoint.<init>(WebsocketClientEndpoint.java:60)
Details:
When I am connected to my internal work network and try to make a websocket connection I initially get connected but then I am sending a TCP reset. If I throw the code on my laptop and connect over a different network like my home Comcast connection the connection is made and I receive the initial data response from the server. I then take my laptop and hook it up to my internal work network and I go back to getting the handshake error.
I have been unable to resolve it yet with my internal security team as we don't do websocket development here so the knowledge base is a little lacking.
I set my proxy prior to calling this routine from my main. It has been verified that I am getting connected to the server but then I am sending a reset. Here is the code I am executing:
try {
System.setProperty("javax.net.debug", "all");
ClientManager client = ClientManager.createClient();
final SSLContextConfigurator defaultConfig = new SSLContextConfigurator();
defaultConfig.retrieve(System.getProperties());
SSLEngineConfigurator sslEngine = new SSLEngineConfigurator(defaultConfig, true, false, false);
client.getProperties().put(ClientProperties.SSL_ENGINE_CONFIGURATOR, sslEngine);
client.getProperties().put(ClientProperties.LOG_HTTP_UPGRADE, true);
client.connectToServer(new Endpoint() {
#Override
public void onOpen(Session session, EndpointConfig config) {
session.addMessageHandler(new MessageHandler.Whole<String>() {
#Override
public void onMessage(String message) {
System.out.println(message);
}
});
}
}, ClientEndpointConfig.Builder.create().build(),
new URI("wss://api.sandbox.gemini.com/v1/marketdata/BTCUSD"));
} catch (Exception e) {
throw new RuntimeException(e);
}
I have read all the posts/questions/answers that I have been able to find but haven't come up with anything yet. I am somewhat limited on what I can personally do on our network as we have pretty tight security but I can work with my security team to find answers if I get asked a question.
I would think it has to be internal to my work network and the proxy maybe but I haven't been able to resolve it. Also, this is the last part of the log information from the connection and error reporting:
Padded plaintext after DECRYPTION: len = 170
0000: 48 54 54 50 2F 31 2E 31 20 34 32 36 20 55 70 67 HTTP/1.1 426 Upg
0010: 72 61 64 65 20 52 65 71 75 69 72 65 64 0D 0A 44 rade Required..D
0020: 61 74 65 3A 20 4D 6F 6E 2C 20 31 32 20 4A 75 6E ate: Mon, 12 Jun
0030: 20 32 30 31 37 20 31 36 3A 35 30 3A 32 35 20 47 2017 16:50:25 G
0040: 4D 54 0D 0A 53 65 72 76 65 72 3A 20 6E 67 69 6E MT..Server: ngin
0050: 78 0D 0A 43 6F 6E 6E 65 63 74 69 6F 6E 3A 20 4B x..Connection: K
0060: 65 65 70 2D 41 6C 69 76 65 0D 0A 43 6F 6E 74 65 eep-Alive..Conte
0070: 6E 74 2D 54 79 70 65 3A 20 74 65 78 74 2F 70 6C nt-Type: text/pl
0080: 61 69 6E 3B 20 63 68 61 72 73 65 74 3D 75 74 66 ain; charset=utf
0090: 2D 38 0D 0A 43 6F 6E 74 65 6E 74 2D 4C 65 6E 67 -8..Content-Leng
00A0: 74 68 3A 20 32 39 0D 0A 0D 0A th: 29....
[Raw read (bb)]: length = 58
0000: 17 03 03 00 35 EC 0F C3 40 0D 18 B4 7B 53 C6 2D ....5...#....S.-
0010: F5 83 29 72 15 51 AC 31 8F 86 52 C9 3C 98 BB F8 ..)r.Q.1..R.<...
0020: 94 4A D7 3A 6E 17 8C 75 9E 58 25 0B AE B5 2F 13 .J.:n..u.X%.../.
0030: 8C 44 29 94 2F 4A 46 18 C9 1A .D)./JF...
Padded plaintext after DECRYPTION: len = 29
0000: 55 70 67 72 61 64 65 20 74 6F 20 57 65 62 53 6F Upgrade to WebSo
0010: 63 6B 65 74 20 72 65 71 75 69 72 65 64 cket required
> Session 6f920826-4b05-47bd-8cad-212038ff9fad [86 ms]: Sending handshake request:
> GET wss://api.sandbox.gemini.com/v1/marketdata/BTCUSD
> Connection: Upgrade
> Host: api.sandbox.gemini.com
> Origin: api.sandbox.gemini.com
> Sec-WebSocket-Key: nkgv7uk/bPSKBiOz5T/Bdg==
> Sec-WebSocket-Version: 13
> Upgrade: websocket
< Session 6f920826-4b05-47bd-8cad-212038ff9fad [600 ms]: Received handshake response:
< 426
< connection: Keep-Alive
< content-length: 29
< content-type: text/plain; charset=utf-8
< date: Mon, 12 Jun 2017 16:50:25 GMT
< server: nginx
If you got this far, thanks...
Adding sniffer information from my network team:
You establish a connection Pkt 263, which you are going through the proxy server, mcweb-a 170.137.249.117. Then you transmit data. The reset is sent in Pkt 280.
enter image description here
In case anyone comes across this. The issue was a problem with my proxy server. We had to add the specific endpoint as being allowable so it would skip some of the security checks.

Fine Uploader 5.11.10 SignatureDoesNotMatch with PHP & AWS S3

UPDATED POST AND RETURN INFO
I'm new to FineUploader and I'm running into problems when uploading files to AWS s3. S3 responds with <Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message> I've tried many different options and parameters and have currently paired it down to a very simple configuration but still get the same response. I've followed the steps in the documentation for setting up fineuploder and the PHP signature endpoint for signing, gone through countless options/settings, looked at various posts but nothing has quite got me to a solution.
The js is simplified down to:
var s3Uploader = new qq.s3.FineUploader({
debug: true,
element: document.getElementById('fine_uploader'),
request: {
endpoint: 'https://bucketname.s3.amazonaws.com',
accessKey: 'KEY'
},
cors: {
expected: true,
sendCredentials: true
},
signature: {
endpoint: 'https://domain/s3/endpoint',
version: 4
},
uploadSuccess: {
endpoint: 'https://domain/s3/endpointsuccess'
},
iframeSupport: {
localBlankPagePath: 'https://domain/s3/blank'
},
thumbnails: {
placeholders: {
notAvailablePath: "https://domain/not_available-generic.png",
waitingPath: "https://domain/waiting-generic.png"
}
}
});
The endpoint-cors.php file for signing requests is identical to that found on Github FineUploader/php-s3-server/endpoint-cors.php dated Nov 5, 2015.
FineUploder submits the following to my endpoint for signing:
{"expiration":"2016-12-30T16:58:27.028Z","conditions":[{"acl":"private"},{"bucket":"bucketname"},{"Content-Type":"application/pdf"},{"success_action_status":"200"},{"x-amz-algorithm":"AWS4-HMAC-SHA256"},{"key":"2c6ed85e-1d5f-45e3-8458-e864f92a8cf3.pdf"},{"x-amz-credential":"KEY/20161230/us-east-1/s3/aws4_request"},{"x-amz-date":"20161230T165327Z"},{"x-amz-meta-qqfilename":"DefaultDocument.pdf"}]}
My signing endpoint responds with:
{"policy":"eyJleHBpcmF0aW9uIjoiMjAxNi0xMi0zMFQxNjo1ODoyNy4wMjhaIiwiY29uZGl0aW9ucyI6W3siYWNsIjoicHJpdmF0ZSJ9LHsiYnVja2V0IjoidXBsb2FkdG9idWlsZGVycG9wIn0seyJDb250ZW50LVR5cGUiOiJhcHBsaWNhdGlvblwvcGRmIn0seyJzdWNjZXNzX2FjdGlvbl9zdGF0dXMiOiIyMDAifSx7IngtYW16LWFsZ29yaXRobSI6IkFXUzQtSE1BQy1TSEEyNTYifSx7ImtleSI6IjJjNmVkODVlLTFkNWYtNDVlMy04NDU4LWU4NjRmOTJhOGNmMy5wZGYifSx7IngtYW16LWNyZWRlbnRpYWwiOiJBS0lBSjRaNlRWRDVVNTZOUzVRUVwvMjAxNjEyMzBcL3VzLWVhc3QtMVwvczNcL2F3czRfcmVxdWVzdCJ9LHsieC1hbXotZGF0ZSI6IjIwMTYxMjMwVDE2NTMyN1oifSx7IngtYW16LW1ldGEtcXFmaWxlbmFtZSI6IkRlZmF1bHREb2N1bWVudC5wZGYifV19","signature":"01dd1e6ab8be148c9f26b8721a267f41d0b4e1d6ac1da7ca3f5a1cc8ab9888e3"}
AWS S3 POST information for file upload:
Request URL:https://bucketname.s3.amazonaws.com/
Request Method:POST
Status Code:403 Forbidden
Remote Address:ipaddress:443
Response Headers
Access-Control-Allow-Methods:POST, PUT, DELETE
Access-Control-Allow-Origin:*
Access-Control-Expose-Headers:ETag
Access-Control-Max-Age:3000
Connection:close
Content-Type:application/xml
Date:Fri, 30 Dec 2016 16:53:29 GMT
Server:AmazonS3
Transfer-Encoding:chunked
Vary:Origin, Access-Control-Request-Headers, Access-Control-Request-Method
x-amz-id-2:lQOge5d8wTNIwH1g3TE/IuNPXNad29p6PbC8DHPDTPZzWvS9eTK6wE5nd2K6Kt/f+FsH9B0oBRw=
x-amz-request-id:E9A9C61173E13568
Request Headers
Accept:*/*
Accept-Encoding:gzip, deflate, br
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Content-Length:659510
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryiz1gbHgrB4vnnG1m
Host:bucketname.s3.amazonaws.com
Origin:https://domain
Referer:https://domain/create/?pt=O1&pid=mFflJn
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
Request Payload
------WebKitFormBoundaryiz1gbHgrB4vnnG1m
Content-Disposition: form-data; name="key"
2c6ed85e-1d5f-45e3-8458-e864f92a8cf3.pdf
------WebKitFormBoundaryiz1gbHgrB4vnnG1m
Content-Disposition: form-data; name="Content-Type"
application/pdf
------WebKitFormBoundaryiz1gbHgrB4vnnG1m
Content-Disposition: form-data; name="success_action_status"
200
------WebKitFormBoundaryiz1gbHgrB4vnnG1m
Content-Disposition: form-data; name="acl"
private
------WebKitFormBoundaryiz1gbHgrB4vnnG1m
Content-Disposition: form-data; name="x-amz-meta-qqfilename"
DefaultDocument.pdf
------WebKitFormBoundaryiz1gbHgrB4vnnG1m
Content-Disposition: form-data; name="x-amz-algorithm"
AWS4-HMAC-SHA256
------WebKitFormBoundaryiz1gbHgrB4vnnG1m
Content-Disposition: form-data; name="x-amz-credential"
AKIAJ4Z6TVD5U56NS5QQ/20161230/us-east-1/s3/aws4_request
------WebKitFormBoundaryiz1gbHgrB4vnnG1m
Content-Disposition: form-data; name="x-amz-date"
20161230T165327Z
------WebKitFormBoundaryiz1gbHgrB4vnnG1m
Content-Disposition: form-data; name="policy"
eyJleHBpcmF0aW9uIjoiMjAxNi0xMi0zMFQxNjo1ODoyNy4wMjhaIiwiY29uZGl0aW9ucyI6W3siYWNsIjoicHJpdmF0ZSJ9LHsiYnVja2V0IjoidXBsb2FkdG9idWlsZGVycG9wIn0seyJDb250ZW50LVR5cGUiOiJhcHBsaWNhdGlvblwvcGRmIn0seyJzdWNjZXNzX2FjdGlvbl9zdGF0dXMiOiIyMDAifSx7IngtYW16LWFsZ29yaXRobSI6IkFXUzQtSE1BQy1TSEEyNTYifSx7ImtleSI6IjJjNmVkODVlLTFkNWYtNDVlMy04NDU4LWU4NjRmOTJhOGNmMy5wZGYifSx7IngtYW16LWNyZWRlbnRpYWwiOiJBS0lBSjRaNlRWRDVVNTZOUzVRUVwvMjAxNjEyMzBcL3VzLWVhc3QtMVwvczNcL2F3czRfcmVxdWVzdCJ9LHsieC1hbXotZGF0ZSI6IjIwMTYxMjMwVDE2NTMyN1oifSx7IngtYW16LW1ldGEtcXFmaWxlbmFtZSI6IkRlZmF1bHREb2N1bWVudC5wZGYifV19
------WebKitFormBoundaryiz1gbHgrB4vnnG1m
Content-Disposition: form-data; name="x-amz-signature"
01dd1e6ab8be148c9f26b8721a267f41d0b4e1d6ac1da7ca3f5a1cc8ab9888e3
------WebKitFormBoundaryiz1gbHgrB4vnnG1m
Content-Disposition: form-data; name="file"; filename="DefaultDocument.pdf"
Content-Type: application/pdf
------WebKitFormBoundaryiz1gbHgrB4vnnG1m--
AWS S3 POST RESPONSE:
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message><AWSAccessKeyId>AKIAJ4Z6TVD5U56NS5QQ</AWSAccessKeyId><StringToSign>eyJleHBpcmF0aW9uIjoiMjAxNi0xMi0zMFQxNjo1ODoyNy4wMjhaIiwiY29uZGl0aW9ucyI6W3siYWNsIjoicHJpdmF0ZSJ9LHsiYnVja2V0IjoidXBsb2FkdG9idWlsZGVycG9wIn0seyJDb250ZW50LVR5cGUiOiJhcHBsaWNhdGlvblwvcGRmIn0seyJzdWNjZXNzX2FjdGlvbl9zdGF0dXMiOiIyMDAifSx7IngtYW16LWFsZ29yaXRobSI6IkFXUzQtSE1BQy1TSEEyNTYifSx7ImtleSI6IjJjNmVkODVlLTFkNWYtNDVlMy04NDU4LWU4NjRmOTJhOGNmMy5wZGYifSx7IngtYW16LWNyZWRlbnRpYWwiOiJBS0lBSjRaNlRWRDVVNTZOUzVRUVwvMjAxNjEyMzBcL3VzLWVhc3QtMVwvczNcL2F3czRfcmVxdWVzdCJ9LHsieC1hbXotZGF0ZSI6IjIwMTYxMjMwVDE2NTMyN1oifSx7IngtYW16LW1ldGEtcXFmaWxlbmFtZSI6IkRlZmF1bHREb2N1bWVudC5wZGYifV19</StringToSign><SignatureProvided>01dd1e6ab8be148c9f26b8721a267f41d0b4e1d6ac1da7ca3f5a1cc8ab9888e3</SignatureProvided><StringToSignBytes>65 79 4a 6c 65 48 42 70 63 6d 46 30 61 57 39 75 49 6a 6f 69 4d 6a 41 78 4e 69 30 78 4d 69 30 7a 4d 46 51 78 4e 6a 6f 31 4f 44 6f 79 4e 79 34 77 4d 6a 68 61 49 69 77 69 59 32 39 75 5a 47 6c 30 61 57 39 75 63 79 49 36 57 33 73 69 59 57 4e 73 49 6a 6f 69 63 48 4a 70 64 6d 46 30 5a 53 4a 39 4c 48 73 69 59 6e 56 6a 61 32 56 30 49 6a 6f 69 64 58 42 73 62 32 46 6b 64 47 39 69 64 57 6c 73 5a 47 56 79 63 47 39 77 49 6e 30 73 65 79 4a 44 62 32 35 30 5a 57 35 30 4c 56 52 35 63 47 55 69 4f 69 4a 68 63 48 42 73 61 57 4e 68 64 47 6c 76 62 6c 77 76 63 47 52 6d 49 6e 30 73 65 79 4a 7a 64 57 4e 6a 5a 58 4e 7a 58 32 46 6a 64 47 6c 76 62 6c 39 7a 64 47 46 30 64 58 4d 69 4f 69 49 79 4d 44 41 69 66 53 78 37 49 6e 67 74 59 57 31 36 4c 57 46 73 5a 32 39 79 61 58 52 6f 62 53 49 36 49 6b 46 58 55 7a 51 74 53 45 31 42 51 79 31 54 53 45 45 79 4e 54 59 69 66 53 78 37 49 6d 74 6c 65 53 49 36 49 6a 4a 6a 4e 6d 56 6b 4f 44 56 6c 4c 54 46 6b 4e 57 59 74 4e 44 56 6c 4d 79 30 34 4e 44 55 34 4c 57 55 34 4e 6a 52 6d 4f 54 4a 68 4f 47 4e 6d 4d 79 35 77 5a 47 59 69 66 53 78 37 49 6e 67 74 59 57 31 36 4c 57 4e 79 5a 57 52 6c 62 6e 52 70 59 57 77 69 4f 69 4a 42 53 30 6c 42 53 6a 52 61 4e 6c 52 57 52 44 56 56 4e 54 5a 4f 55 7a 56 52 55 56 77 76 4d 6a 41 78 4e 6a 45 79 4d 7a 42 63 4c 33 56 7a 4c 57 56 68 63 33 51 74 4d 56 77 76 63 7a 4e 63 4c 32 46 33 63 7a 52 66 63 6d 56 78 64 57 56 7a 64 43 4a 39 4c 48 73 69 65 43 31 68 62 58 6f 74 5a 47 46 30 5a 53 49 36 49 6a 49 77 4d 54 59 78 4d 6a 4d 77 56 44 45 32 4e 54 4d 79 4e 31 6f 69 66 53 78 37 49 6e 67 74 59 57 31 36 4c 57 31 6c 64 47 45 74 63 58 46 6d 61 57 78 6c 62 6d 46 74 5a 53 49 36 49 6b 52 6c 5a 6d 46 31 62 48 52 45 62 32 4e 31 62 57 56 75 64 43 35 77 5a 47 59 69 66 56 31 39</StringToSignBytes><RequestId>E9A9C61173E13568</RequestId><HostId>lQOge5d8wTNIwH1g3TE/IuNPXNad29p6PbC8DHPDTPZzWvS9eTK6wE5nd2K6Kt/f+FsH9B0oBRw=</HostId></Error>
Comparison of the endpoint signature and the AWS S3 POST response appear the same signature and policy are being submitted.
Response Snipets:
endpoint response: {....,"signature":"01dd1e6ab8be148c9f26b8721a267f41d0b4e1d6ac1da7ca3f5a1cc8ab9888e3"}
AWS S3 response: <SignatureProvided>01dd1e6ab8be148c9f26b8721a267f41d0b4e1d6ac1da7ca3f5a1cc8ab9888e3</SignatureProvided>
endpoint policy: eyJleHBpcmF0aW9uIjoiMjAxNi0xMi0zMFQxNjo1ODoyNy4wMjhaIiwiY29uZGl0aW9ucyI6W3siYWNsIjoicHJpdmF0ZSJ9LHsiYnVja2V0IjoidXBsb2FkdG9idWlsZGVycG9wIn0seyJDb250ZW50LVR5cGUiOiJhcHBsaWNhdGlvblwvcGRmIn0seyJzdWNjZXNzX2FjdGlvbl9zdGF0dXMiOiIyMDAifSx7IngtYW16LWFsZ29yaXRobSI6IkFXUzQtSE1BQy1TSEEyNTYifSx7ImtleSI6IjJjNmVkODVlLTFkNWYtNDVlMy04NDU4LWU4NjRmOTJhOGNmMy5wZGYifSx7IngtYW16LWNyZWRlbnRpYWwiOiJBS0lBSjRaNlRWRDVVNTZOUzVRUVwvMjAxNjEyMzBcL3VzLWVhc3QtMVwvczNcL2F3czRfcmVxdWVzdCJ9LHsieC1hbXotZGF0ZSI6IjIwMTYxMjMwVDE2NTMyN1oifSx7IngtYW16LW1ldGEtcXFmaWxlbmFtZSI6IkRlZmF1bHREb2N1bWVudC5wZGYifV19
S3 Response: <StringToSign>eyJleHBpcmF0aW9uIjoiMjAxNi0xMi0zMFQxNjo1ODoyNy4wMjhaIiwiY29uZGl0aW9ucyI6W3siYWNsIjoicHJpdmF0ZSJ9LHsiYnVja2V0IjoidXBsb2FkdG9idWlsZGVycG9wIn0seyJDb250ZW50LVR5cGUiOiJhcHBsaWNhdGlvblwvcGRmIn0seyJzdWNjZXNzX2FjdGlvbl9zdGF0dXMiOiIyMDAifSx7IngtYW16LWFsZ29yaXRobSI6IkFXUzQtSE1BQy1TSEEyNTYifSx7ImtleSI6IjJjNmVkODVlLTFkNWYtNDVlMy04NDU4LWU4NjRmOTJhOGNmMy5wZGYifSx7IngtYW16LWNyZWRlbnRpYWwiOiJBS0lBSjRaNlRWRDVVNTZOUzVRUVwvMjAxNjEyMzBcL3VzLWVhc3QtMVwvczNcL2F3czRfcmVxdWVzdCJ9LHsieC1hbXotZGF0ZSI6IjIwMTYxMjMwVDE2NTMyN1oifSx7IngtYW16LW1ldGEtcXFmaWxlbmFtZSI6IkRlZmF1bHREb2N1bWVudC5wZGYifV19</StringToSign>
Thanks for any help you provide.

How do I connect to a websocket manually, with netcat/socat/telnet?

I am trying to connect to the reference websocket echo server "manually", in order to learn how the protocol works (I am using socat for that). However, the server invariably closes the connection without providing an answer. Any idea why?
Here is what I do:
socat - TCP:echo.websocket.org:80
Then, I paste the following text in the terminal:
GET /?encoding=text HTTP/1.1
Origin: http://www.websocket.org
Connection: Upgrade
Host: echo.websocket.org
Sec-WebSocket-Key: P7Kp2hTLNRPFMGLxPV47eQ==
Upgrade: websocket
Sec-WebSocket-Version: 13
I sniffed the parameters of the connection with the developer tools, in firefox, on the same machine, where this works flawlessly: therefore, I would assume they are correct. However after that, the server closes the connection immediately, without providing an answer. Why? How can I implement the protocol "manually"?
I would like type test in my terminal and get the server to reply with what I typed (It works in a web browser).
I think you want to modify the socket stream to translate \n (line feed) to CRLF (Carriage return & line feed). Doing info socat produces detailed information which includes this modifier:
crnl Converts the default line termination character NL ('\n', 0x0a)
to/from CRNL ("\r\n", 0x0d0a) when writing/reading on this chan-
nel (example). Note: socat simply strips all CR characters.
So I think you should be able to do this:
socat - TCP:echo.websocket.org:80,crnl
I'd like to add that my WebSocket tool websocat can help in debugging the WebSocket protocol, especially when combined with socat:
$ websocat - ws-c:sh-c:"socat -v -x - tcp:echo.websocket.org:80" --ws-c-uri ws://echo.websocket.org
> 2018/07/03 16:30:06.021658 length=157 from=0 to=156
47 45 54 20 2f 20 48 54 54 50 2f 31 2e 31 0d 0a GET / HTTP/1.1..
48 6f 73 74 3a 20 65 63 68 6f 2e 77 65 62 73 6f Host: echo.webso
63 6b 65 74 2e 6f 72 67 0d 0a cket.org..
43 6f 6e 6e 65 63 74 69 6f 6e 3a 20 55 70 67 72 Connection: Upgr
61 64 65 0d 0a ade..
55 70 67 72 61 64 65 3a 20 77 65 62 73 6f 63 6b Upgrade: websock
65 74 0d 0a et..
53 65 63 2d 57 65 62 53 6f 63 6b 65 74 2d 56 65 Sec-WebSocket-Ve
72 73 69 6f 6e 3a 20 31 33 0d 0a rsion: 13..
53 65 63 2d 57 65 62 53 6f 63 6b 65 74 2d 4b 65 Sec-WebSocket-Ke
79 3a 20 59 76 36 32 44 31 57 6d 7a 79 79 31 65 y: Yv62D1Wmzyy1e
69 6d 62 47 6d 68 69 61 67 3d 3d 0d 0a imbGmhiag==..
0d 0a ..
--
< 2018/07/03 16:30:06.164057 length=201 from=0 to=200
48 54 54 50 2f 31 2e 31 20 31 30 31 20 57 65 62 HTTP/1.1 101 Web
20 53 6f 63 6b 65 74 20 50 72 6f 74 6f 63 6f 6c Socket Protocol
20 48 61 6e 64 73 68 61 6b 65 0d 0a Handshake..
43 6f 6e 6e 65 63 74 69 6f 6e 3a 20 55 70 67 72 Connection: Upgr
61 64 65 0d 0a ade..
44 61 74 65 3a 20 54 75 65 2c 20 30 33 20 4a 75 Date: Tue, 03 Ju
6c 20 32 30 31 38 20 31 33 3a 31 35 3a 30 30 20 l 2018 13:15:00
47 4d 54 0d 0a GMT..
53 65 63 2d 57 65 62 53 6f 63 6b 65 74 2d 41 63 Sec-WebSocket-Ac
63 65 70 74 3a 20 55 56 6a 32 74 35 50 43 7a 62 cept: UVj2t5PCzb
58 49 32 52 4e 51 75 70 2f 71 48 31 63 5a 44 6e XI2RNQup/qH1cZDn
38 3d 0d 0a 8=..
53 65 72 76 65 72 3a 20 4b 61 61 7a 69 6e 67 20 Server: Kaazing
47 61 74 65 77 61 79 0d 0a Gateway..
55 70 67 72 61 64 65 3a 20 77 65 62 73 6f 63 6b Upgrade: websock
65 74 0d 0a et..
0d 0a ..
--
ABCDEF
> 2018/07/03 16:30:12.707919 length=13 from=157 to=169
82 87 40 57 f5 88 01 15 b6 cc 05 11 ff ..#W.........
--
< 2018/07/03 16:30:12.848398 length=9 from=201 to=209
82 07 41 42 43 44 45 46 0a ..ABCDEF.
--
ABCDEF
> 2018/07/03 16:30:14.528333 length=6 from=170 to=175
88 80 18 ec 05 a8 ......
--
< 2018/07/03 16:30:14.671629 length=2 from=210 to=211
88 00 ..
--
In case of failures with manually driven socat -v -x - TCP:echo.websocket.org:80,crnl (mentioned in the other answer), you can compare it with WebSocat-driven socat like in session depicted above.
Reverse (server) example with socat debug dump:
socat -v -x tcp-l:1234,fork,reuseaddr exec:'websocat -t ws-u\:stdio\: mirror\:'
Alternatively, here is a way to connect and read the stream from a wss secure websocket stream from the command line using solely core php.
php -r '$sock=stream_socket_client("tls://echo.websocket.org:443",$e,$n,30,STREAM_CLIENT_CONNECT,stream_context_create(null));if(!$sock){echo"[$n]$e".PHP_EOL;}else{fwrite($sock,"GET / HTTP/1.1\r\nHost: echo.websocket.org\r\nAccept: */*\r\nConnection: Upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Key: ".rand(0,999)."\r\n\r\n");while(!feof($sock)){var_dump(fgets($sock,2048));}}'
Other similar example, pulling from another wss server: (Do not get rekt)
php -r '$sock=stream_socket_client("tls://stream.binance.com:9443",$e,$n,30,STREAM_CLIENT_CONNECT,stream_context_create(null));if(!$sock){echo"[$n]$e".PHP_EOL;}else{fwrite($sock,"GET /stream?streams=btcusdt#kline_1m HTTP/1.1\r\nHost: stream.binance.com:9443\r\nAccept: */*\r\nConnection: Upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Key: ".rand(0,999)."\r\n\r\n");while(!feof($sock)){var_dump(explode(",",fgets($sock,512)));}}'

NGINX, FastCGI, UTF-8 Encoding: Output iso-8859-1 instead of utf8

i hope you can give me an idea about what's going wrong.
The Szenario:
I run gitweb (CGI) with a script in fastcgi mode:
#!/bin/sh
export FCGI_SOCKET_PATH=127.0.0.1:7001
su git -c "/var/www/vh_[vhost]/htdocs/gitweb.cgi --fastcgi &"
Then i use nginx to serve that content:
...
fastcgi_pass 127.0.0.1:7001;
...
Everything works as expected, but here's the problem:
$ wget "http://git.[host].de/?p=[repo].git;a=summary" -O /tmp/test.txt && file --mime-encoding /tmp/test.txt
> /tmp/test.txt: iso-8859-1
$ su git -c "./gitweb.cgi \"?p=[repo].git;a=summary\" > ./test" && file --mime-encoding ./test
> ./test: utf-8
Which obviously means that fast-cgi output is utf8 while content served by nginx is iso-8859-1.
FireBugs Response Header:
Server nginx
Date Fri, 02 Sep 2011 14:14:08 GMT
Content-Type application/xhtml+xml; charset=utf-8
Transfer-Encoding chunked
Connection close
It looks like the transfer using the socket leads to an encoding problem.
I've tested a lot but can't figure out how to solve this.
although you aren't using PHP, I found the fix for my issue but wrapping the pieces that were being exposed as ISO-8859-1 with: utf8_encode(): http://php.net/manual/en/function.utf8-encode.php
If your CGI is in PERL, maybe http://perldoc.perl.org/utf8.html will solve your problem. It solved mine ... Z�rich
Another option could be to add the following to the http { } statement in your nginx.conf:
charset utf-8;
-sd
I can make it works by using fcgiwrap.
I though some environment variables where different between the two methods, so I added the following code to the gitweb.cgi dispatch() sub:
open my $tmplogfile, ">", "/tmp/gitweb-env.txt";
foreach my $varkey (sort keys %ENV) {
print $tmplogfile "$varkey = $ENV{$varkey}\n";
}
close $tmplogfile;
but the environment were the same.
Something may be done by fcgiwrap, I do not yet found what.
Here are the commands I use and the differences I found using tcpdump on the fcgi socket:
# gitweb spawned by fcgiwrap outputs utf-8
/usr/bin/spawn-fcgi -d /usr/share/gitweb -a 127.0.0.1 -p 3000 -u www-data -g gitolite -P /run/gitweb/gitweb.cgi.pid -- /usr/sbin/fcgiwrap
# Require the following nginx gitweb_fastcgi_params
# fastcgi_param QUERY_STRING $query_string;
# fastcgi_param REQUEST_METHOD $request_method;
# fastcgi_param SCRIPT_NAME $fastcgi_script_name;
# fastcgi_param DOCUMENT_ROOT $document_root;
# With the following nginx configuration
# upstream gitweb {
# server 127.0.0.1:3000;
# }
#
# server {
# listen 80;
#
# server_name git.example.net;
#
# root /usr/share/gitweb;
#
# access_log /var/log/nginx/gitweb-access.log;
# error_log /var/log/nginx/gitweb-errors.log;
#
# location / {
# alias /usr/share/gitweb/gitweb.cgi;
# include gitweb_fastcgi_params;
# fastcgi_pass gitweb;
# }
#
# location /static {
# alias /usr/share/gitweb/static;
# expires 31d;
# }
# }
# STDOUT captured on lo
# Begin of the FCGI answer
# 00000000 01 06 00 01 1f f8 00 00 53 74 61 74 75 73 3a 20 ........ Status:
# 00000010 32 30 30 20 4f 4b 0d 0a 43 6f 6e 74 65 6e 74 2d 200 OK.. Content-
# 00000020 54 79 70 65 3a 20 61 70 70 6c 69 63 61 74 69 6f Type: ap plicatio
# 00000030 6e 2f 78 68 74 6d 6c 2b 78 6d 6c 3b 20 63 68 61 n/xhtml+ xml; cha
# 00000040 72 73 65 74 3d 75 74 66 2d 38 0d 0a 0d 0a 3c 3f rset=utf -8....<?
# 00000050 78 6d 6c 20 76 65 72 73 69 6f 6e 3d 22 31 2e 30 xml vers ion="1.0
# [...]
#
# "Guido Günther" as UTF-8
# 00000FA0 6c 65 3d 22 53 65 61 72 63 68 20 66 6f 72 20 63 le="Sear ch for c
# 00000FB0 6f 6d 6d 69 74 73 20 61 75 74 68 6f 72 65 64 20 ommits a uthored
# 00000FC0 62 79 20 47 75 69 64 6f 20 47 c3 bc 6e 74 68 65 by Guido G..nthe
# 00000FD0 72 22 20 63 6c 61 73 73 3d 22 6c 69 73 74 22 20 r" class ="list"
Before, gitweb --fastcgi was directly spawned by spawn-fcgi:
# gitweb spawned by spawn-fcgi outputs iso-8859-1
/usr/bin/spawn-fcgi -d /usr/share/gitweb -a 127.0.0.1 -p 3000 -u www-data -g gitolite -P /run/gitweb/gitweb.cgi.pid -- /usr/share/gitweb/gitweb.cgi --fastcgi
# STDOUT captured on lo
# Begin of the FCGI answer with "00 46 02" in place of "1f f8 00" for utf-8 output
# 00000000 01 06 00 01 00 46 02 00 53 74 61 74 75 73 3a 20 .....F.. Status:
# 00000010 32 30 30 20 4f 4b 0d 0a 43 6f 6e 74 65 6e 74 2d 200 OK.. Content-
# 00000020 54 79 70 65 3a 20 61 70 70 6c 69 63 61 74 69 6f Type: ap plicatio
# 00000030 6e 2f 78 68 74 6d 6c 2b 78 6d 6c 3b 20 63 68 61 n/xhtml+ xml; cha
# 00000040 72 73 65 74 3d 75 74 66 2d 38 0d 0a 0d 0a 00 00 rset=utf -8......
# 00000050 01 06 00 01 02 88 00 00 3c 3f 78 6d 6c 20 76 65 ........ <?xml ve
# 00000060 72 73 69 6f 6e 3d 22 31 2e 30 22 20 65 6e 63 6f rsion="1 .0" enco
# 00000070 64 69 6e 67 3d 22 75 74 66 2d 38 22 3f 3e 0a 3c ding="ut f-8"?>.<
# [...]
#
# "Guido Günther" as ISO-8859-1
# 00001128 74 6c 65 3d 22 53 65 61 72 63 68 20 66 6f 72 20 tle="Sea rch for
# 00001138 63 6f 6d 6d 69 74 73 20 61 75 74 68 6f 72 65 64 commits authored
# 00001148 20 62 79 20 47 75 69 64 6f 20 47 fc 6e 74 68 65 by Guid o G.nthe

Resources