git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: Returning error message from custom smart http server

From
Bryan Turner <bturner@atlassian.com>
Date
May 19, 2014, 08:12 UTC
Message-ID
<CAGyf7-EoSgTxZzReFArOgcrBaARv7fRiZTMPZX+Loy9dec23aQ@mail.gmail.com>
In-Reply-To
<20140516230116.GC180798@vauxhall.crustytoothpaste.net>

On Sat, May 17, 2014 at 9:01 AM, brian m. carlson <sandals@crustytoothpaste.net> wrote:

Show 20 quoted lines
> On Tue, May 13, 2014 at 09:39:59AM +0200, "Ákos, Tajti" wrote:
>> Dear List,
>>
>> we implemented our own git smart http server to be able to check permissions
>> and other thing before pushes. It works fine, however, the error messages we
>> generate on the server side are not displayed by the command line client. On
>> the server we generate error messages like this:
>>
>>         response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
>>         response.getWriter().write(msg);
>>
>> On the command line we get this:
>>
>> Total 0 (delta 0), reused 0 (delta 0)
>> POST git-receive-pack (290 bytes)
>> efrror: RPC failed; result=22, HTTP code = 401
>> atal: The remote end hung up unexpectedly
>> fatal: The remote end hung up unexpectedly
>>
>> The server message is completely missing. Is there a solution for this?

You should not need a patched git; the wire protocol itself has a mechanism for sending "smart" error messages. It's not particularly _obvious_, but it's there.

For starters, to return an error message, your status must be 200 OK. You can't return any other status code or Git will interpret your error as some form of _HTTP_ error rather than a _git_ error.

In the smart protocol the client sends a service to the server as a
query parameter, like "?service=git-receive-pack". For such a request,
you need to:
- Set the content type to "application/x-<service>-advertisement"
(e.g. "application/x-git-receive-pack-advertisement") (Not all command
line Git versions require this, but JGit does)
- Set the status code as 200 OK
- Write back a payload where the first 4 bytes are the hex-encoded
length of the text (where "FFFF" is max length for a single packet).
Note that the 4 bytes for the size are _part_ of that length, so if
you're writing "Test" the length is 8, not 4
- After the size, you write "# service=<service>" (e.g. "#
service=git-receive-pack"; note the space after the #) This is the
metadata. For an error, you don't really have much to say.
- After that, an empty packet, which is "0000" (four zeros) This
separates the metadata from the ref advertisement
- After that you can write your message, beginning with "ERR " (note
the trailing space there). The "ERR " tells Git what you're writing
isn't a ref, it's an error. I'd recommend appending a newline (and add
1 more to your length for it), because when Git echoes your error
message it doesn't seem to do that

I'm not sure whether there's a document that describes all of this; I found it by digging into the Git source code (you can find the "ERR" handling in connect.c, get_remote_heads). This may be exploiting the protocol, I'll leave that to someone more knowledgeable on how they _intended_ this all to be used, but it works for us.

A full example looks something like this: "0036# service=git-receive-pack0000ERR This is a test\n"

Hope this helps, Bryan Turner

Show 35 quoted lines
>
> It does look that way.  Does the following patch work for you?
>
> -- >8 --
> Subject: [PATCH] http: provide server's error message on RPC failure
>
> The server might provide a custom error message that is useful to the user.
> Provide this message to the user if HTTP RPC fails.
>
> Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
> ---
>  remote-curl.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/remote-curl.c b/remote-curl.c
> index 52c2d96..5984d35 100644
> --- a/remote-curl.c
> +++ b/remote-curl.c
> @@ -426,8 +426,8 @@ static int run_slot(struct active_request_slot *slot,
>         err = run_one_slot(slot, results);
>
>         if (err != HTTP_OK && err != HTTP_REAUTH) {
> -               error("RPC failed; result=%d, HTTP code = %ld",
> -                     results->curl_result, results->http_code);
> +               error("RPC failed; result=%d, HTTP code = %ld (%s)",
> +                     results->curl_result, results->http_code, curl_errorstr);
>         }
>
>         return err;
> -- >8 --
>
> --
> brian m. carlson / brian with sandals: Houston, Texas, US
> +1 832 623 2791 | http://www.crustytoothpaste.net/~bmc | My opinion only
> OpenPGP: RSA v4 4096b: 88AC E9B2 9196 305B A994 7552 F1BA 225C 0223 B187
Previous: brian m. carlsonNext: Carlos Martín Nieto
Message 3 of 5 in “Returning error message from custom smart http server”
  1. Ákos, TajtiMay 13, 2014
  2. brian m. carlsonMay 16, 2014
  3. Bryan TurnerMay 19, 2014
  4. Carlos Martín NietoMay 19, 2014
  5. Jeff KingMay 19, 2014

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.