18

Currently writing a synchronization mechanism over HTTP, I started to build my server on NodeJS, which looked like a good solution.

So Ok, I can get GET and HEAD methods working. But as soon as I try to use non standard methods, for example "SYNC". Here's the code:

var http = require("http");
var server = http.createServer(function (req, res) {
    res.writeHead(200);
    res.end(req.method);
});
server.listen(8080);

Looks alright... let's telnet this, issue a GET and then a SYNC request

mylaptop:~ aob$ telnet localhost 8080
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET / HTTP/1.1

HTTP/1.1 200 OK
Connection: keep-alive
Transfer-Encoding: chunked

3
GET
0

SYNC / HTTP/1.1
Connection closed by foreign host.

Any idea on how I can get SYNC to work ?

aspyct
  • 3,625
  • 7
  • 36
  • 61
  • 1
    Well, I eventually solved this by adding my HTTP method to the source itself. You need to alter the http_parser.c and node_http_parser.c that you can find in the source package. Then recompile and have fun. – aspyct Apr 30 '12 at 13:03
  • nice! Would you mind posting your solution? – mikermcneil Sep 08 '13 at 07:07
  • Hi :) More than a year later, I'm afraid I lost that source code. But it was quite straightforward, so you can probably solve it by following the short instructions above. – aspyct Sep 09 '13 at 07:42
  • @aspyct, do you where this relevant code to add custom HTTP-method exists in current version of NodeJS? – VoidPointer Dec 14 '15 at 07:45
  • @VoidPointer it's been ages since I worked with nodejs. No idea where it is now, sorry. – aspyct Dec 14 '15 at 08:53
  • Updated the answer with the location of the http methods according to the current nodejs version: https://github.com/nodejs/node/blob/master/deps/http_parser/http_parser.c#L961 – admix Dec 15 '15 at 16:46

2 Answers2

10

Edit: The http parser has since been updated and changed quite a lot. Because of this, it's not quite as straight-forward to add custom HTTP methods, but thanks to @admix - here's the relevant entry point in node 5.x:

    switch (ch) {
      case 'A': parser->method = HTTP_ACL; break;
      case 'B': parser->method = HTTP_BIND; break;
      case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break;
      case 'D': parser->method = HTTP_DELETE; break;
      case 'G': parser->method = HTTP_GET; break;
      case 'H': parser->method = HTTP_HEAD; break;
      case 'L': parser->method = HTTP_LOCK; /* or LINK */ break;
      case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH, MKCALENDAR */ break;
      case 'N': parser->method = HTTP_NOTIFY; break;
      case 'O': parser->method = HTTP_OPTIONS; break;
      case 'P': parser->method = HTTP_POST;
        /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */
        break;
      case 'R': parser->method = HTTP_REPORT; /* or REBIND */ break;
      case 'S': parser->method = HTTP_SUBSCRIBE; /* or SEARCH */ break;
      case 'T': parser->method = HTTP_TRACE; break;
      case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE, UNBIND, UNLINK */ break;
      default:
        SET_ERRNO(HPE_INVALID_METHOD);
        goto error;
    }

Original reply:

You would have to patch node in order to add arbitrary methods. See the relevant source lines:

static inline Persistent<String>
method_to_str(unsigned short m) {
  switch (m) {
    case HTTP_DELETE:     return delete_sym;
    case HTTP_GET:        return get_sym;
    case HTTP_HEAD:       return head_sym;
    case HTTP_POST:       return post_sym;
    case HTTP_PUT:        return put_sym;
    case HTTP_CONNECT:    return connect_sym;
    case HTTP_OPTIONS:    return options_sym;
    case HTTP_TRACE:      return trace_sym;
    case HTTP_PATCH:      return patch_sym;
    case HTTP_COPY:       return copy_sym;
    case HTTP_LOCK:       return lock_sym;
    case HTTP_MKCOL:      return mkcol_sym;
    case HTTP_MOVE:       return move_sym;
    case HTTP_PROPFIND:   return propfind_sym;
    case HTTP_PROPPATCH:  return proppatch_sym;
    case HTTP_UNLOCK:     return unlock_sym;
    case HTTP_REPORT:     return report_sym;
    case HTTP_MKACTIVITY: return mkactivity_sym;
    case HTTP_CHECKOUT:   return checkout_sym;
    case HTTP_MERGE:      return merge_sym;
    case HTTP_MSEARCH:    return msearch_sym;
    case HTTP_NOTIFY:     return notify_sym;
    case HTTP_SUBSCRIBE:  return subscribe_sym;
    case HTTP_UNSUBSCRIBE:return unsubscribe_sym;
    default:              return unknown_method_sym;
  }
}
Linus Thiel
  • 38,647
  • 9
  • 109
  • 104
  • 1
    Gustav, the code base of nodejs has changed now, NodeJS is currently at 5.2.0. So I couldn't find any relevant code in the file. Can you help to understand whether this is moved to some other file in src/? Simple grep didn't help.. – VoidPointer Dec 14 '15 at 07:44
  • Sorry I know the codebase no better than you. Good luck. – Linus Thiel Dec 14 '15 at 08:57
5

According to current nodejs version (5.2.0), you can find the HTTP METHODS in here, which you can customize:

https://github.com/nodejs/node/blob/master/deps/http_parser/http_parser.c#L961

Relevant code:

parser->method = (enum http_method) 0;
    parser->index = 1;
    switch (ch) {
      case 'A': parser->method = HTTP_ACL; break;
      case 'B': parser->method = HTTP_BIND; break;
      case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break;
      case 'D': parser->method = HTTP_DELETE; break;
      case 'G': parser->method = HTTP_GET; break;
      case 'H': parser->method = HTTP_HEAD; break;
      case 'L': parser->method = HTTP_LOCK; /* or LINK */ break;
      case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH, MKCALENDAR */ break;
      case 'N': parser->method = HTTP_NOTIFY; break;
      case 'O': parser->method = HTTP_OPTIONS; break;
      case 'P': parser->method = HTTP_POST;
        /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */
        break;
      case 'R': parser->method = HTTP_REPORT; /* or REBIND */ break;
      case 'S': parser->method = HTTP_SUBSCRIBE; /* or SEARCH */ break;
      case 'T': parser->method = HTTP_TRACE; break;
      case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE, UNBIND, UNLINK */ break;
      default:
        SET_ERRNO(HPE_INVALID_METHOD);
        goto error;
    }
    UPDATE_STATE(s_req_method);
admix
  • 1,752
  • 3
  • 22
  • 27
  • Awarding the bounty to this answer, assuming from the votes that it's a good choice (I don't know anything about the technology, I started the bounty as a favour to a Meta user.) – Pekka Dec 21 '15 at 10:20