shlist

share and manage lists between multiple people
Log | Files | Refs

commit 631cf31e15452e4910cdaea490693bf4a168f40c
parent b0f4154357620a22ea77d29a450659b80b9220e3
Author: Kyle Milz <kyle@0x30.net>
Date:   Tue,  2 Feb 2016 23:10:08 -0700

apnd: get a go client working

- ironically it was quicker to learn a new language and implement a http2 client
  than it was to just do it in perl
- this implementation has a unix socket server that accepts local connections
  and then sends out requests over http2
- this should please the apple overlords

Diffstat:
Dapnd/apnd | 141-------------------------------------------------------------------------------
Aapnd/apnd.go | 97+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 97 insertions(+), 141 deletions(-)

diff --git a/apnd/apnd b/apnd/apnd @@ -1,141 +0,0 @@ -#!/usr/bin/perl -use strict; -use warnings; - -use AnyEvent; -use AnyEvent::Socket; -use AnyEvent::Handle; -use Net::SSLeay; -use AnyEvent::TLS; - -use Protocol::HTTP2; -use Protocol::HTTP2::Client; -use Protocol::HTTP2::Constants qw(const_name); - -Net::SSLeay::initialize(); - -my $client = Protocol::HTTP2::Client->new( - on_change_state => sub { - my ( $stream_id, $previous_state, $current_state ) = @_; - printf "Stream %i changed state from %s to %s\n", - $stream_id, const_name( "states", $previous_state ), - const_name( "states", $current_state ); - }, - on_push => sub { - my ($push_headers) = @_; - - # If we accept PUSH_PROMISE - # return callback to receive promised data - # return undef otherwise - print "Server want to push some resource to us\n"; - - return sub { - my ( $headers, $data ) = @_; - print "Received promised resource\n"; - } - }, - on_error => sub { - my $error = shift; - printf "Error occured: %s\n", const_name( "errors", $error ); - } -); - -my $host = 'api.development.push.apple.com'; -my $port = 443; - -# Prepare http/2 request -$client->request( - ':scheme' => "https", - ':authority' => $host . ":" . $port, - ':path' => "/3/device/devid_goes_here", - ':method' => "POST", - # headers => [ - # 'accept' => '*/*', - # 'user-agent' => 'perl-Protocol-HTTP2/0.01', - # ], - on_done => sub { - my ( $headers, $data ) = @_; - printf "Get headers. Count: %i\n", scalar(@$headers) / 2; - printf "Get data. Length: %i\n", length($data); - print $data; - }, - - data => "hello=world&test=done", -); - -my $w = AnyEvent->condvar; - -tcp_connect $host, $port, sub { - my ($fh) = @_ or do { - print "connection failed: $!\n"; - $w->send; - return; - }; - - my $tls; - eval { - $tls = AnyEvent::TLS->new( - method => "TLSv1_2", - cert_file => 'ssl/aps.pem', - key_file => 'ssl/aps.key' - ); - - # ALPN (Net-SSLeay > 1.55, openssl >= 1.0.2) - if ( exists &Net::SSLeay::CTX_set_alpn_protos ) { - Net::SSLeay::CTX_set_alpn_protos( $tls->ctx, - [Protocol::HTTP2::ident_tls] ); - } - - # NPN (Net-SSLeay > 1.45, openssl >= 1.0.1) - elsif ( exists &Net::SSLeay::CTX_set_next_proto_select_cb ) { - Net::SSLeay::CTX_set_next_proto_select_cb( $tls->ctx, - [Protocol::HTTP2::ident_tls] ); - } - else { - die "ALPN and NPN is not supported\n"; - } - }; - if ($@) { - print "Some problem with SSL CTX: $@\n"; - $w->send; - return; - } - - my $handle; - $handle = AnyEvent::Handle->new( - fh => $fh, - tls => "connect", - tls_ctx => $tls, - autocork => 1, - on_error => sub { - $_[0]->destroy; - print "connection error\n"; - $w->send; - }, - on_eof => sub { - $handle->destroy; - $w->send; - } - ); - - # First write preface to peer - while ( my $frame = $client->next_frame ) { - $handle->push_write($frame); - } - - $handle->on_read( - sub { - my $handle = shift; - - $client->feed( $handle->{rbuf} ); - - $handle->{rbuf} = undef; - while ( my $frame = $client->next_frame ) { - $handle->push_write($frame); - } - $handle->push_shutdown if $client->shutdown; - } - ); -}; - -$w->recv; diff --git a/apnd/apnd.go b/apnd/apnd.go @@ -0,0 +1,97 @@ +package main + +import ( + "bytes" + "crypto/tls" + "crypto/x509" + "encoding/json" + "fmt" + //"io" + "log" + "net/http" + "net" + + "golang.org/x/net/http2" +) + +func echo_server(c net.Conn, h http.Client) { + buf := make([]byte, 4096) + nr, err := c.Read(buf); + if err != nil { + return + } + + var f interface{} + + data := buf[0:nr] + fmt.Printf("Received: %v", string(data)) + err = json.Unmarshal(data, &f) + + m := f.(map[string]interface{}) + + for k, v := range m { + switch vv := v.(type) { + case string: + fmt.Println(k, "is string", vv) + case int: + fmt.Println(k, "is int", vv) + case []interface{}: + fmt.Println(k, "is an array", vv) + for i, u := range vv { + fmt.Println(i, u) + } + default: + fmt.Println(k, "is of a type I don't know how to handle") + } + } + + var jsonStr = []byte(`{"aps":{"badge":33},"other_key":"other_value"}`) + + req, err := http.NewRequest("POST", "https://api.development.push.apple.com/3/device/DE2D368BB6C80E1D8BCB86D20CB6C2161BD5CEC5BA35A1E1AA0DB382849ED9B2", bytes.NewBuffer(jsonStr)) + req.Header.Set("apns-topic", "com.octopus.shlist") + resp, err := h.Do(req) + fmt.Println("response was:", resp) + + c.Close() +} + +func main() { + cert, err := tls.LoadX509KeyPair("ssl/aps.pem", "ssl/aps.key") + if err != nil { + log.Fatalf("server: loadkeys: %s", err) + } + + config := tls.Config{Certificates: []tls.Certificate{cert}, InsecureSkipVerify: true} + conn, err := tls.Dial("tcp", "api.development.push.apple.com:443", &config) + if err != nil { + log.Fatalf("client: dial: %s", err) + } + defer conn.Close() + log.Println("client: connected to: ", conn.RemoteAddr()) + + state := conn.ConnectionState() + for _, v := range state.PeerCertificates { + fmt.Println(x509.MarshalPKIXPublicKey(v.PublicKey)) + fmt.Println(v.Subject) + } + log.Println("client: handshake: ", state.HandshakeComplete) + log.Println("client: mutual: ", state.NegotiatedProtocolIsMutual) + + client := http.Client { + Transport: &http2.Transport{TLSClientConfig: &config}, + } + + l, err := net.Listen("unix", "../apnd.socket") + if err != nil { + log.Fatal("listen error:", err) + } + + for { + fd, err := l.Accept() + if err != nil { + log.Fatal("accept error:", err) + } + + go echo_server(fd, client) + } +}