github.com/hyperledger/aries-framework-go@v0.3.2/pkg/didcomm/messaging/service/http/httpmsgsvc.go (about) 1 /* 2 * 3 * Copyright SecureKey Technologies Inc. All Rights Reserved. 4 * 5 * SPDX-License-Identifier: Apache-2.0 6 * / 7 * 8 */ 9 10 // Package http provides http-over-didcomm message service features. 11 // 12 // Any incoming message of type "https://didcomm.org/http-over-didcomm/1.0/request" and matching purpose can be handled 13 // by registering 'OverDIDComm' message service. 14 // 15 // RFC Reference: 16 // 17 // https://github.com/hyperledger/aries-rfcs/blob/master/features/0335-http-over-didcomm/README.md 18 // https://github.com/hyperledger/aries-rfcs/blob/master/features/0351-purpose-decorator/README.md 19 // 20 package http 21 22 import ( 23 "bytes" 24 "encoding/base64" 25 "fmt" 26 "net/http" 27 28 "github.com/hyperledger/aries-framework-go/pkg/common/log" 29 "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/service" 30 "github.com/hyperledger/aries-framework-go/pkg/internal/logutil" 31 ) 32 33 const ( 34 // OverDIDCommSpec is http over DIDComm Spec value. 35 OverDIDCommSpec = "https://didcomm.org/http-over-didcomm/1.0/" 36 37 // OverDIDCommMsgRequestType is http over DIDComm request message type. 38 OverDIDCommMsgRequestType = OverDIDCommSpec + "request" 39 40 // error messages. 41 errNameAndHandleMandatory = "service name and http request handle is mandatory" 42 errFailedToDecodeMsg = "unable to decode DID comm message: %w" 43 errFailedToDecodeBody = "unable to decode message body: %w" 44 errFailedToCreateNewRequest = "failed to create http request from incoming message: %w" 45 46 httpMessage = "httpMessage" 47 ) 48 49 var logger = log.New("aries-framework/httpmsg") 50 51 // RequestHandle handle function for http over did comm message service which gets called by 52 // `OverDIDComm` message service to handle matching incoming request. 53 // 54 // Args 55 // 56 // msgID : message ID of incoming message. 57 // request: http request derived from incoming DID comm message. 58 // 59 // Returns 60 // 61 // error : handle can return error back to service to notify message dispatcher about failures. 62 type RequestHandle func(msgID string, request *http.Request) error 63 64 // NewOverDIDComm creates new HTTP over DIDComm message service which serves 65 // incoming DIDComm message over HTTP. DIDComm message receiver of [RFC-0351] 66 // 67 // Reference: 68 // 69 // https://github.com/hyperledger/aries-rfcs/blob/master/features/0335-http-over-didcomm/README.md 70 // https://github.com/hyperledger/aries-rfcs/blob/master/features/0351-purpose-decorator/README.md 71 // 72 // Args: 73 // 74 // name - is name of this message service (this is mandatory argument). 75 // 76 // purpose - is optional list of purposes to be handled by this message service. If not provided then only message type 77 // will be taken into consideration in acceptance criteria of this message service. 78 // 79 // httpHandle - is handle function to which incoming DIDComm message will be sent after being converted to 80 // http request. (this is mandatory argument). 81 // 82 // Returns: 83 // 84 // OverDIDComm: http over didcomm message service, 85 // 86 // error: arg validation errors. 87 func NewOverDIDComm(name string, httpHandle RequestHandle, purpose ...string) (*OverDIDComm, error) { 88 if name == "" || httpHandle == nil { 89 return nil, fmt.Errorf(errNameAndHandleMandatory) 90 } 91 92 return &OverDIDComm{ 93 name: name, 94 purpose: purpose, 95 httpHandle: httpHandle, 96 }, nil 97 } 98 99 // OverDIDComm is message service which transports incoming DIDComm message over to 100 // intended http resource providers. 101 type OverDIDComm struct { 102 name string 103 purpose []string 104 httpHandle RequestHandle 105 } 106 107 // Name of HTTP over DIDComm message service. 108 func (m *OverDIDComm) Name() string { 109 return m.name 110 } 111 112 // Accept is acceptance criteria for this HTTP over DIDComm message service, 113 // it accepts http-didcomm-over message type [RFC-0335] and follows `A tagging system` purpose field validation 114 // from RFC-0351. 115 func (m *OverDIDComm) Accept(msgType string, purpose []string) bool { 116 if msgType != OverDIDCommMsgRequestType { 117 return false 118 } 119 120 // if purpose not set, then match only message type. 121 if len(m.purpose) == 0 { 122 return true 123 } 124 125 // match purpose if provided 126 for _, msgPurpose := range purpose { 127 for _, svcPurpose := range m.purpose { 128 if msgPurpose == svcPurpose { 129 return true 130 } 131 } 132 } 133 134 return false 135 } 136 137 // HandleInbound for HTTP over DIDComm message service. 138 func (m *OverDIDComm) HandleInbound(msg service.DIDCommMsg, _ service.DIDCommContext) (string, error) { 139 svcMsg := httpOverDIDCommMsg{} 140 141 err := msg.Decode(&svcMsg) 142 if err != nil { 143 return "", fmt.Errorf(errFailedToDecodeMsg, err) 144 } 145 146 rqBody, err := base64.StdEncoding.DecodeString(svcMsg.BodyB64) 147 if err != nil { 148 return "", fmt.Errorf(errFailedToDecodeBody, err) 149 } 150 151 // create request 152 request, err := http.NewRequest(svcMsg.Method, svcMsg.ResourceURI, bytes.NewBuffer(rqBody)) 153 if err != nil { 154 return "", fmt.Errorf(errFailedToCreateNewRequest, err) 155 } 156 157 // add headers 158 for _, header := range svcMsg.Headers { 159 request.Header.Add(header.Name, header.Value) 160 } 161 162 logutil.LogDebug(logger, httpMessage, "handleInbound", "received", 163 logutil.CreateKeyValueString("msgType", msg.Type()), 164 logutil.CreateKeyValueString("msgID", msg.ID())) 165 166 // TODO implement http version switch based on `msg.Version` [Issue:#1110] 167 168 return "", m.httpHandle(msg.ID(), request) 169 }