add server implement
parent
6716b30f3f
commit
3396a7519d
@ -0,0 +1,132 @@
|
||||
#include "_nghttp2.h"
|
||||
|
||||
static ssize_t server_send_callback(nghttp2_session *session,
|
||||
const uint8_t *data, size_t length,
|
||||
int flags, void *user_data)
|
||||
{
|
||||
return ServerDataSend(user_data, (void *)data, length);
|
||||
}
|
||||
|
||||
static int on_server_frame_recv_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
void *user_data)
|
||||
{
|
||||
switch (frame->hd.type)
|
||||
{
|
||||
case NGHTTP2_HEADERS:
|
||||
if (frame->headers.cat == NGHTTP2_HCAT_REQUEST)
|
||||
{
|
||||
OnServerHeadersDoneCallback(user_data, frame->hd.stream_id);
|
||||
}
|
||||
case NGHTTP2_DATA:
|
||||
if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM)
|
||||
{
|
||||
OnServerStreamEndCallback(user_data, frame->hd.stream_id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int on_server_stream_close_callback(nghttp2_session *session,
|
||||
int32_t stream_id,
|
||||
uint32_t error_code,
|
||||
void *user_data)
|
||||
|
||||
{
|
||||
OnServerStreamClose(user_data, stream_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int on_server_header_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value,
|
||||
size_t valuelen, uint8_t flags,
|
||||
void *user_data)
|
||||
{
|
||||
switch (frame->hd.type)
|
||||
{
|
||||
case NGHTTP2_HEADERS:
|
||||
if (frame->headers.cat == NGHTTP2_HCAT_REQUEST)
|
||||
{
|
||||
OnServerHeaderCallback(user_data, frame->hd.stream_id,
|
||||
(void *)name, namelen, (void *)value, valuelen);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int on_server_data_chunk_recv_callback(nghttp2_session *session,
|
||||
uint8_t flags,
|
||||
int32_t stream_id,
|
||||
const uint8_t *data,
|
||||
size_t len, void *user_data)
|
||||
{
|
||||
return OnServerDataRecv(user_data, stream_id, (void *)data, len);
|
||||
}
|
||||
|
||||
static int on_server_begin_headers_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
void *user_data)
|
||||
{
|
||||
|
||||
switch (frame->hd.type)
|
||||
{
|
||||
case NGHTTP2_HEADERS:
|
||||
if (frame->headers.cat == NGHTTP2_HCAT_REQUEST)
|
||||
{
|
||||
OnServerBeginHeaderCallback(user_data, frame->hd.stream_id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
nghttp2_session *init_server_session(size_t data)
|
||||
{
|
||||
nghttp2_session_callbacks *callbacks;
|
||||
nghttp2_session *session;
|
||||
|
||||
nghttp2_session_callbacks_new(&callbacks);
|
||||
|
||||
nghttp2_session_callbacks_set_send_callback(callbacks, server_send_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks,
|
||||
on_server_frame_recv_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_stream_close_callback(
|
||||
callbacks, on_server_stream_close_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
|
||||
callbacks, on_server_data_chunk_recv_callback);
|
||||
nghttp2_session_callbacks_set_on_header_callback(callbacks,
|
||||
on_server_header_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_begin_headers_callback(
|
||||
callbacks, on_server_begin_headers_callback);
|
||||
|
||||
nghttp2_session_server_new(&session, callbacks, (void *)((int *)(data)));
|
||||
|
||||
nghttp2_session_callbacks_del(callbacks);
|
||||
return session;
|
||||
}
|
||||
|
||||
int send_server_connection_header(nghttp2_session *session)
|
||||
{
|
||||
nghttp2_settings_entry iv[1] = {
|
||||
{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}};
|
||||
int rv;
|
||||
|
||||
rv = nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv,
|
||||
ARRLEN(iv));
|
||||
return rv;
|
||||
/*
|
||||
if (rv != 0) {
|
||||
// warnx("Fatal error: %s", nghttp2_strerror(rv));
|
||||
return rv;
|
||||
}
|
||||
return 0;
|
||||
*/
|
||||
}
|
@ -0,0 +1,438 @@
|
||||
package nghttp2
|
||||
|
||||
/*
|
||||
#cgo pkg-config: libnghttp2
|
||||
#include "_nghttp2.h"
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// ServerConn server connection
|
||||
type ServerConn struct {
|
||||
// Handler handler to handle request
|
||||
Handler http.Handler
|
||||
|
||||
session *C.nghttp2_session
|
||||
streams map[int]*ServerStream
|
||||
lock *sync.Mutex
|
||||
conn net.Conn
|
||||
errch chan struct{}
|
||||
exitch chan struct{}
|
||||
err error
|
||||
}
|
||||
|
||||
// ServerStream server stream
|
||||
type ServerStream struct {
|
||||
streamID int
|
||||
// headers receive done
|
||||
headersDone bool
|
||||
// is stream_end flag received
|
||||
streamEnd bool
|
||||
// request
|
||||
req *http.Request
|
||||
// response header
|
||||
header http.Header
|
||||
// response statusCode
|
||||
statusCode int
|
||||
// response has send
|
||||
responseSend bool
|
||||
|
||||
// server connection
|
||||
conn *ServerConn
|
||||
|
||||
// data provider
|
||||
dp *dataProvider
|
||||
cdp *C.nghttp2_data_provider
|
||||
|
||||
closed bool
|
||||
//buf *bytes.Buffer
|
||||
}
|
||||
|
||||
type bodyProvider struct {
|
||||
buf *bytes.Buffer
|
||||
closed bool
|
||||
lock *sync.Mutex
|
||||
}
|
||||
|
||||
func (bp *bodyProvider) Read(buf []byte) (int, error) {
|
||||
for {
|
||||
bp.lock.Lock()
|
||||
n, err := bp.buf.Read(buf)
|
||||
bp.lock.Unlock()
|
||||
if err != nil && !bp.closed {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
|
||||
func (bp *bodyProvider) Write(buf []byte) (int, error) {
|
||||
bp.lock.Lock()
|
||||
defer bp.lock.Unlock()
|
||||
return bp.buf.Write(buf)
|
||||
}
|
||||
|
||||
func (bp *bodyProvider) Close() error {
|
||||
/*
|
||||
if c, ok := bp.w.(io.Closer); ok{
|
||||
return c.Close()
|
||||
}
|
||||
*/
|
||||
bp.closed = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewServerConn create new server connection
|
||||
func NewServerConn(c net.Conn, handler http.Handler) (*ServerConn, error) {
|
||||
conn := &ServerConn{
|
||||
conn: c,
|
||||
Handler: handler,
|
||||
streams: make(map[int]*ServerStream),
|
||||
lock: new(sync.Mutex),
|
||||
errch: make(chan struct{}),
|
||||
exitch: make(chan struct{}),
|
||||
}
|
||||
conn.session = C.init_server_session(C.size_t(uintptr(unsafe.Pointer(conn))))
|
||||
if conn.session == nil {
|
||||
return nil, fmt.Errorf("init session failed")
|
||||
}
|
||||
//log.Println("send server connection header")
|
||||
ret := C.send_server_connection_header(conn.session)
|
||||
if int(ret) < 0 {
|
||||
log.Println(C.GoString(C.nghttp2_strerror(ret)))
|
||||
return nil, fmt.Errorf("send connection header failed")
|
||||
}
|
||||
//go conn.run()
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (c *ServerConn) serve(s *ServerStream) {
|
||||
var handler = c.Handler
|
||||
if c.Handler == nil {
|
||||
handler = http.DefaultServeMux
|
||||
}
|
||||
handler.ServeHTTP(s, s.req)
|
||||
s.Close()
|
||||
}
|
||||
|
||||
// Close close the server connection
|
||||
func (c *ServerConn) Close() error {
|
||||
for _, s := range c.streams {
|
||||
s.Close()
|
||||
}
|
||||
C.nghttp2_session_terminate_session(c.session, 0)
|
||||
C.nghttp2_session_del(c.session)
|
||||
close(c.exitch)
|
||||
c.conn.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Run run the server loop
|
||||
func (c *ServerConn) Run() {
|
||||
var wantRead int
|
||||
var wantWrite int
|
||||
var delay = 50
|
||||
var ret C.int
|
||||
|
||||
defer c.Close()
|
||||
defer close(c.errch)
|
||||
|
||||
datach := make(chan []byte)
|
||||
errch := make(chan error)
|
||||
|
||||
go func() {
|
||||
buf := make([]byte, 16*1024)
|
||||
readloop:
|
||||
for {
|
||||
select {
|
||||
case <-c.exitch:
|
||||
break readloop
|
||||
default:
|
||||
}
|
||||
|
||||
n, err := c.conn.Read(buf)
|
||||
if err != nil {
|
||||
errch <- err
|
||||
break
|
||||
}
|
||||
datach <- buf[:n]
|
||||
}
|
||||
}()
|
||||
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
case <-c.errch:
|
||||
break loop
|
||||
case err := <-errch:
|
||||
c.err = err
|
||||
break loop
|
||||
case <-c.exitch:
|
||||
break loop
|
||||
default:
|
||||
}
|
||||
|
||||
wantWrite = int(C.nghttp2_session_want_write(c.session))
|
||||
if wantWrite != 0 {
|
||||
ret = C.nghttp2_session_send(c.session)
|
||||
if int(ret) < 0 {
|
||||
c.err = fmt.Errorf("sesion send error: %s",
|
||||
C.GoString(C.nghttp2_strerror(ret)))
|
||||
log.Println(c.err)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
wantRead = int(C.nghttp2_session_want_read(c.session))
|
||||
select {
|
||||
case d := <-datach:
|
||||
d1 := C.CBytes(d)
|
||||
ret1 := C.nghttp2_session_mem_recv(c.session,
|
||||
(*C.uchar)(d1), C.size_t(int(len(d))))
|
||||
C.free(d1)
|
||||
if int(ret1) < 0 {
|
||||
c.err = fmt.Errorf("sesion recv error: %s",
|
||||
C.GoString(C.nghttp2_strerror(ret)))
|
||||
log.Println(c.err)
|
||||
break loop
|
||||
}
|
||||
default:
|
||||
}
|
||||
|
||||
// make delay when no data read/write
|
||||
if wantRead == 0 && wantWrite == 0 {
|
||||
select {
|
||||
case <-time.After(time.Duration(delay) * time.Millisecond):
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write implements http.ResponseWriter
|
||||
func (s *ServerStream) Write(buf []byte) (int, error) {
|
||||
if !s.responseSend {
|
||||
s.WriteHeader(http.StatusOK)
|
||||
}
|
||||
/*
|
||||
//log.Printf("stream %d, send %d bytes", s.streamID, len(buf))
|
||||
if s.buf.Len() > 2048 {
|
||||
s.dp.Write(s.buf.Bytes())
|
||||
s.buf.Reset()
|
||||
}
|
||||
|
||||
if len(buf) < 2048 {
|
||||
s.buf.Write(buf)
|
||||
return len(buf), nil
|
||||
}
|
||||
*/
|
||||
return s.dp.Write(buf)
|
||||
}
|
||||
|
||||
// WriteHeader implements http.ResponseWriter
|
||||
func (s *ServerStream) WriteHeader(code int) {
|
||||
s.statusCode = code
|
||||
nvIndex := 0
|
||||
nvMax := 25
|
||||
nva := C.new_nv_array(C.size_t(nvMax))
|
||||
setNvArray(nva, nvIndex, ":status", fmt.Sprintf("%d", code), 0)
|
||||
nvIndex++
|
||||
|
||||
for k, v := range s.header {
|
||||
if strings.ToLower(k) == "host" {
|
||||
continue
|
||||
}
|
||||
//log.Printf("header %s: %s", k, v)
|
||||
setNvArray(nva, nvIndex, strings.Title(k), v[0], 0)
|
||||
nvIndex++
|
||||
}
|
||||
var dp *dataProvider
|
||||
var cdp *C.nghttp2_data_provider
|
||||
dp, cdp = newDataProvider()
|
||||
dp.streamID = s.streamID
|
||||
dp.session = s.conn.session
|
||||
s.dp = dp
|
||||
s.cdp = cdp
|
||||
ret := C.nghttp2_submit_response(
|
||||
s.conn.session, C.int(s.streamID), nva.nv, C.size_t(nvIndex), cdp)
|
||||
C.delete_nv_array(nva)
|
||||
if int(ret) < 0 {
|
||||
panic(fmt.Sprintf("sumit response error %s", C.GoString(C.nghttp2_strerror(ret))))
|
||||
}
|
||||
s.responseSend = true
|
||||
log.Printf("stream %d send response", s.streamID)
|
||||
}
|
||||
|
||||
// Header implements http.ResponseWriter
|
||||
func (s *ServerStream) Header() http.Header {
|
||||
if s.header == nil {
|
||||
s.header = http.Header{}
|
||||
}
|
||||
return s.header
|
||||
}
|
||||
|
||||
// Close close the stream
|
||||
func (s *ServerStream) Close() error {
|
||||
if s.closed {
|
||||
return nil
|
||||
}
|
||||
//C.nghttp2_submit_rst_stream(s.conn.session, 0, C.int(s.streamID), 0)
|
||||
s.req.Body.Close()
|
||||
if s.dp != nil {
|
||||
s.dp.Close()
|
||||
}
|
||||
s.closed = true
|
||||
log.Printf("stream %d closed", s.streamID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ServerDataRecv callback function for receive data from network
|
||||
//export ServerDataRecv
|
||||
func ServerDataRecv(ptr unsafe.Pointer, data unsafe.Pointer,
|
||||
length C.size_t) C.ssize_t {
|
||||
conn := (*ServerConn)(ptr)
|
||||
buf := make([]byte, int(length))
|
||||
n, err := conn.conn.Read(buf)
|
||||
if err != nil {
|
||||
return -1
|
||||
}
|
||||
cbuf := C.CBytes(buf[:n])
|
||||
defer C.free(cbuf)
|
||||
C.memcpy(data, cbuf, C.size_t(n))
|
||||
return C.ssize_t(n)
|
||||
}
|
||||
|
||||
// ServerDataSend callback function for send data to network
|
||||
//export ServerDataSend
|
||||
func ServerDataSend(ptr unsafe.Pointer, data unsafe.Pointer,
|
||||
length C.size_t) C.ssize_t {
|
||||
//log.Println("server data send")
|
||||
conn := (*ServerConn)(ptr)
|
||||
buf := C.GoBytes(data, C.int(length))
|
||||
n, err := conn.conn.Write(buf)
|
||||
if err != nil {
|
||||
return -1
|
||||
}
|
||||
//log.Println("send ", n, " bytes to network ", buf)
|
||||
return C.ssize_t(n)
|
||||
}
|
||||
|
||||
// OnServerDataRecv callback function for data recv
|
||||
//export OnServerDataRecv
|
||||
func OnServerDataRecv(ptr unsafe.Pointer, streamID C.int,
|
||||
data unsafe.Pointer, length C.size_t) C.int {
|
||||
conn := (*ServerConn)(ptr)
|
||||
s := conn.streams[int(streamID)]
|
||||
bp := s.req.Body.(*bodyProvider)
|
||||
buf := C.GoBytes(data, C.int(length))
|
||||
bp.Write(buf)
|
||||
return C.int(length)
|
||||
}
|
||||
|
||||
// OnServerBeginHeaderCallback callback function for begin header
|
||||
//export OnServerBeginHeaderCallback
|
||||
func OnServerBeginHeaderCallback(ptr unsafe.Pointer, streamID C.int) C.int {
|
||||
conn := (*ServerConn)(ptr)
|
||||
s := &ServerStream{
|
||||
streamID: int(streamID),
|
||||
conn: conn,
|
||||
req: &http.Request{
|
||||
URL: &url.URL{},
|
||||
Header: http.Header{},
|
||||
Proto: "HTTP/2.0",
|
||||
ProtoMajor: 2,
|
||||
ProtoMinor: 0,
|
||||
},
|
||||
//buf: new(bytes.Buffer),
|
||||
}
|
||||
conn.streams[int(streamID)] = s
|
||||
return 0
|
||||
}
|
||||
|
||||
// OnServerHeaderCallback callback function for header
|
||||
//export OnServerHeaderCallback
|
||||
func OnServerHeaderCallback(ptr unsafe.Pointer, streamID C.int,
|
||||
name unsafe.Pointer, namelen C.int,
|
||||
value unsafe.Pointer, valuelen C.int) C.int {
|
||||
conn := (*ServerConn)(ptr)
|
||||
s := conn.streams[int(streamID)]
|
||||
hdrname := C.GoStringN((*C.char)(name), namelen)
|
||||
hdrvalue := C.GoStringN((*C.char)(value), valuelen)
|
||||
hdrname = strings.ToLower(hdrname)
|
||||
switch hdrname {
|
||||
case ":method":
|
||||
s.req.Method = hdrvalue
|
||||
case ":scheme":
|
||||
s.req.URL.Scheme = hdrvalue
|
||||
case ":path":
|
||||
s.req.RequestURI = hdrvalue
|
||||
u, _ := url.ParseRequestURI(s.req.RequestURI)
|
||||
scheme := s.req.URL.Scheme
|
||||
*(s.req.URL) = *u
|
||||
if scheme != "" {
|
||||
s.req.URL.Scheme = scheme
|
||||
}
|
||||
case ":authority":
|
||||
s.req.Host = hdrvalue
|
||||
default:
|
||||
s.req.Header.Add(hdrname, hdrvalue)
|
||||
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// OnServerStreamEndCallback callback function for frame received
|
||||
//export OnServerStreamEndCallback
|
||||
func OnServerStreamEndCallback(ptr unsafe.Pointer, streamID C.int) C.int {
|
||||
|
||||
conn := (*ServerConn)(ptr)
|
||||
s := conn.streams[int(streamID)]
|
||||
s.streamEnd = true
|
||||
bp := s.req.Body.(*bodyProvider)
|
||||
if s.req.Method != "CONNECT" {
|
||||
bp.closed = true
|
||||
log.Println("stream end flag set, begin to serve")
|
||||
go conn.serve(s)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// OnServerHeadersDoneCallback callback function for all headers received
|
||||
//export OnServerHeadersDoneCallback
|
||||
func OnServerHeadersDoneCallback(ptr unsafe.Pointer, streamID C.int) C.int {
|
||||
conn := (*ServerConn)(ptr)
|
||||
s := conn.streams[int(streamID)]
|
||||
s.headersDone = true
|
||||
bp := &bodyProvider{
|
||||
buf: new(bytes.Buffer),
|
||||
lock: new(sync.Mutex),
|
||||
}
|
||||
s.req.Body = bp
|
||||
if s.req.Method == "CONNECT" {
|
||||
go conn.serve(s)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// OnServerStreamClose callback function for stream close
|
||||
//export OnServerStreamClose
|
||||
func OnServerStreamClose(ptr unsafe.Pointer, streamID C.int) C.int {
|
||||
conn := (*ServerConn)(ptr)
|
||||
s := conn.streams[int(streamID)]
|
||||
conn.lock.Lock()
|
||||
delete(conn.streams, int(streamID))
|
||||
conn.lock.Unlock()
|
||||
s.Close()
|
||||
return 0
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDYDCCAkigAwIBAgIJAJ92ThBK0H0ZMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
|
||||
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
|
||||
aWRnaXRzIFB0eSBMdGQwHhcNMTgwNjI3MDMwMjUwWhcNMjgwNjI0MDMwMjUwWjBF
|
||||
MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
|
||||
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
|
||||
CgKCAQEAufMjhIyoWzqqRKbglkfCWqSbU1N6SPaSjBmVQCfFGzUZx3DHWvemJ8Ip
|
||||
2Nb9Gx9fI/GiRHs1K6noWZjJzsFZNdsoAADg+vXhS4MEwsItcRnKFgbmBtjKPbQy
|
||||
jHnndAy8Wwe73NXTy7oBSbd5CZogvblLjfndSUIhCXVv7+PFHjfG78LEL7Dp1i1A
|
||||
96SV2YuVYHr6FIS6C5FA0FGtGpXUC265jUN+sI88ONXMc/7zQ+4VWggB+Kq3B7uR
|
||||
4DjTtxAC0X58AdWJm3yH6nTJLcsfOVQs1u7Mg97aUpRo9osw7ZMcEEchOw85L0Rl
|
||||
K4vlZDnB2xD+8S8RRQi+Y/4GKPAihwIDAQABo1MwUTAdBgNVHQ4EFgQUGY2IxTxn
|
||||
3tKlRsUnko97fF4X8WYwHwYDVR0jBBgwFoAUGY2IxTxn3tKlRsUnko97fF4X8WYw
|
||||
DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAHpvWRFV+Cen2VQdX
|
||||
OO1YYufqcGPmTxo0XmksOUQsd+vwR0HSjCK1oC0PlloviFvCXn9p4ZvwVK1NdK19
|
||||
RUkiXPAIw5QmXeNQgCJRv7jhObIuqfKVGfZuH8PdPMcPzU+PxgaZ/gnaW62AAFJA
|
||||
frZXwMhr/Ar+CvH4NSZfOxBF4LOWM0eVYfxUOFq+qvYptdSxXyK1kuBxFXOVNEIw
|
||||
CWp75uzvZ1gNaUrdfCNoYMV2qeyuL8gNfRhExrDfjn4ouOZq0Lh8FHCnGdoZo15D
|
||||
ZHkLUqdKnOXtHKdnLcxStF6orKF7I3f3fp5kyRM19uZzLV07zdawVJSDbaO2cJz1
|
||||
Qff5gg==
|
||||
-----END CERTIFICATE-----
|
@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEAufMjhIyoWzqqRKbglkfCWqSbU1N6SPaSjBmVQCfFGzUZx3DH
|
||||
WvemJ8Ip2Nb9Gx9fI/GiRHs1K6noWZjJzsFZNdsoAADg+vXhS4MEwsItcRnKFgbm
|
||||
BtjKPbQyjHnndAy8Wwe73NXTy7oBSbd5CZogvblLjfndSUIhCXVv7+PFHjfG78LE
|
||||
L7Dp1i1A96SV2YuVYHr6FIS6C5FA0FGtGpXUC265jUN+sI88ONXMc/7zQ+4VWggB
|
||||
+Kq3B7uR4DjTtxAC0X58AdWJm3yH6nTJLcsfOVQs1u7Mg97aUpRo9osw7ZMcEEch
|
||||
Ow85L0RlK4vlZDnB2xD+8S8RRQi+Y/4GKPAihwIDAQABAoIBAFUuooin/r+8Ah/s
|
||||
6lktikUHvvfO9+fQvJVdate24D50dti8Ozba18zCz3S8F7qDBoxqttD0OAlGjl/s
|
||||
9BW40Osw+AP4YxfT5182J8ooNbToAYFRq7JbQVo+4CEl/vdUljyFMHQbqChdjxV7
|
||||
7QCPEIyZA5mIauySVJwGpj6YcsZCMemwEVjD3tFEeXF6qu0hD9R4SVDiJEosxta7
|
||||
evzfENVUgfUMceJQzRUQ/3HfbgBJybPfNQ8fH2ORF2eOgjcmlmh+EwXGNcuCCpXd
|
||||
EOndM30YYBRJBCAuvCdPrg9/2H2KL9jsIuLG1PyO9/IiLGMh5nTP/2TYjKOxNcYh
|
||||
1g8S4+ECgYEA8lW1Q9msH1wWM+eZwHDg1rZ3BLMCguRHh2CN/q1KAOgdRsEBsP3A
|
||||
u45MjwwBWzy56H6w69RC4AXQcMdGjZT20095RpYD8Rv1hmaB/1n9mL6i8V2p+X5D
|
||||
pk1EgDDTWy8VbT3jn/Qt8hxINGvKYbZaRQgAtAXPx71mNGgxYLm3+18CgYEAxG93
|
||||
+on9SmhTXZNke+BRrgX0FTpkGtdCwfNnGMGyX7qlNR3kUls17JYE7ejLED7NWxOT
|
||||
uSBCib8Lhh7qhCl+N9rvxpZkeESoZazhoBIigv9osOLOxZtrct1sg7MHDTWgIzT+
|
||||
+OvLzveHPuliVKZVJdM69dz2QUplC9buf0JtUdkCgYAHaA0xNK7pCnR3Q6XUVt7Y
|
||||
UR1UHHCANZ/mCFJurTcszetPJUj68tZ4JQI8AP7tne6Ep5KaspMUq7jSKZUDcMEW
|
||||
dkBbouwd61/Wqr1gY4y3pWPvgpBWWsCQjZ4BWPystcSu4Qxa8CiTVL/0MjMuR1d8
|
||||
8qCq396Y2TYNdf3EWgjAewKBgHUNJyU3zKLl/6cnCR130bQtAAEWRkhoNPN1ot1x
|
||||
rmS0x3UbVs5sY3mS+2T47ufDRIMc603JF10VZjyJd51BTGDkKTTgsQWpg97yYZAM
|
||||
vlvo7e1ZeXTu49wSbXMc3vrUFZRlI/oYJ94wSXsHfvyKEPr1H5EaFfNZ7VRcwsk6
|
||||
QAIhAoGBAOX5gnUHiQe9n8Vg5AZS6JoNf11+ZHemDNczQAZ4o7L0nHvorqeKBZvG
|
||||
U7jo1XDTyrdbs8BPibVdArSpD23auLBL8WZ2wORvFLWXl5po/GSGqoOVS9KoBGMs
|
||||
6E2UkiVR00zYSXTXwsiin3DrLuZcjG7InV45I+ws5DerYFGoNer/
|
||||
-----END RSA PRIVATE KEY-----
|
Loading…
Reference in New Issue