@@ -77,6 +77,127 @@ public static async Task CopyFromAsync(this HttpWebRequest httpWebRequest, Cloud
7777 await stream . CopyToAsync ( httpWebRequest . GetRequestStream ( ) ) ;
7878 }
7979
80+ /// <summary>
81+ /// Handle the request as WebHook validation request
82+ /// </summary>
83+ /// <param name="httpRequestMessage">Request</param>
84+ /// <param name="validateOrigin">Callback that returns whether the given origin may push events. If 'null', all origins are acceptable.</param>
85+ /// <param name="validateRate">Callback that returns the acceptable request rate. If 'null', the rate is not limited.</param>
86+ /// <returns>Response</returns>
87+ public static async Task < HttpResponseMessage > HandleAsWebHookValidationRequest (
88+ this HttpRequestMessage httpRequestMessage , Func < string , bool > validateOrigin ,
89+ Func < string , string > validateRate )
90+ {
91+ if ( IsWebHookValidationRequest ( httpRequestMessage ) )
92+ {
93+ var origin = httpRequestMessage . Headers . GetValues ( "WebHook-Request-Origin" ) . FirstOrDefault ( ) ;
94+ var rate = httpRequestMessage . Headers . GetValues ( "WebHook-Request-Rate" ) . FirstOrDefault ( ) ;
95+
96+ if ( origin != null && ( validateOrigin == null || validateOrigin ( origin ) ) )
97+ {
98+ if ( rate != null )
99+ {
100+ if ( validateRate != null )
101+ {
102+ rate = validateRate ( rate ) ;
103+ }
104+ else
105+ {
106+ rate = "*" ;
107+ }
108+ }
109+
110+ if ( httpRequestMessage . Headers . Contains ( "WebHook-Request-Callback" ) )
111+ {
112+ var uri = httpRequestMessage . Headers . GetValues ( "WebHook-Request-Callback" ) . FirstOrDefault ( ) ;
113+ try
114+ {
115+ HttpClient client = new HttpClient ( ) ;
116+ var response = await client . GetAsync ( new Uri ( uri ) ) ;
117+ return new HttpResponseMessage ( response . StatusCode ) ;
118+ }
119+ catch ( Exception e )
120+ {
121+ return new HttpResponseMessage ( HttpStatusCode . InternalServerError ) ;
122+ }
123+ }
124+ else
125+ {
126+ var response = new HttpResponseMessage ( HttpStatusCode . OK ) ;
127+ response . Headers . Add ( "Allow" , "POST" ) ;
128+ response . Headers . Add ( "WebHook-Allowed-Origin" , origin ) ;
129+ response . Headers . Add ( "WebHook-Allowed-Rate" , rate ) ;
130+ return response ;
131+ }
132+ }
133+ }
134+
135+ return new HttpResponseMessage ( HttpStatusCode . MethodNotAllowed ) ;
136+ }
137+
138+ /// <summary>
139+ /// Handle the request as WebHook validation request
140+ /// </summary>
141+ /// <param name="context">Request context</param>
142+ /// <param name="validateOrigin">Callback that returns whether the given origin may push events. If 'null', all origins are acceptable.</param>
143+ /// <param name="validateRate">Callback that returns the acceptable request rate. If 'null', the rate is not limited.</param>
144+ /// <returns>Task</returns>
145+ public static async Task HandleAsWebHookValidationRequest ( this HttpListenerContext context ,
146+ Func < string , bool > validateOrigin , Func < string , string > validateRate )
147+ {
148+ if ( IsWebHookValidationRequest ( context . Request ) )
149+ {
150+ var origin = context . Request . Headers . Get ( "WebHook-Request-Origin" ) ;
151+ var rate = context . Request . Headers . Get ( "WebHook-Request-Rate" ) ;
152+
153+ if ( origin != null && ( validateOrigin == null || validateOrigin ( origin ) ) )
154+ {
155+ if ( rate != null )
156+ {
157+ if ( validateRate != null )
158+ {
159+ rate = validateRate ( rate ) ;
160+ }
161+ else
162+ {
163+ rate = "*" ;
164+ }
165+ }
166+
167+ if ( context . Request . Headers [ "WebHook-Request-Callback" ] != null )
168+ {
169+ var uri = context . Request . Headers . Get ( "WebHook-Request-Callback" ) ;
170+ try
171+ {
172+ HttpClient client = new HttpClient ( ) ;
173+ var response = await client . GetAsync ( new Uri ( uri ) ) ;
174+ context . Response . StatusCode = ( int ) response . StatusCode ;
175+ context . Response . Close ( ) ;
176+ return ;
177+ }
178+ catch ( Exception e )
179+ {
180+ context . Response . StatusCode = ( int ) HttpStatusCode . InternalServerError ;
181+ context . Response . Close ( ) ;
182+ return ;
183+ }
184+ }
185+ else
186+ {
187+ context . Response . StatusCode = ( int ) HttpStatusCode . OK ;
188+ context . Response . Headers . Add ( "Allow" , "POST" ) ;
189+ context . Response . Headers . Add ( "WebHook-Allowed-Origin" , origin ) ;
190+ context . Response . Headers . Add ( "WebHook-Allowed-Rate" , rate ) ;
191+ context . Response . Close ( ) ;
192+ return ;
193+ }
194+ }
195+ }
196+
197+ context . Response . StatusCode = ( int ) HttpStatusCode . MethodNotAllowed ;
198+ context . Response . Close ( ) ;
199+ }
200+
80201 /// <summary>
81202 /// Indicates whether this HttpResponseMessage holds a CloudEvent
82203 /// </summary>
@@ -101,6 +222,24 @@ public static bool IsCloudEvent(this HttpListenerRequest httpListenerRequest)
101222 httpListenerRequest . Headers [ SpecVersionHttpHeader2 ] != null ;
102223 }
103224
225+ /// <summary>
226+ /// Indicates whether this HttpListenerRequest is a web hook validation request
227+ /// </summary>
228+ public static bool IsWebHookValidationRequest ( this HttpRequestMessage httpRequestMessage )
229+ {
230+ return ( httpRequestMessage . Method . Method . Equals ( "options" , StringComparison . InvariantCultureIgnoreCase ) &&
231+ httpRequestMessage . Headers . Contains ( "WebHook-Request-Origin" ) ) ;
232+ }
233+
234+ /// <summary>
235+ /// Indicates whether this HttpListenerRequest is a web hook validation request
236+ /// </summary>
237+ public static bool IsWebHookValidationRequest ( this HttpListenerRequest httpRequestMessage )
238+ {
239+ return ( httpRequestMessage . HttpMethod . Equals ( "options" , StringComparison . InvariantCultureIgnoreCase ) &&
240+ httpRequestMessage . Headers [ "WebHook-Request-Origin" ] != null ) ;
241+ }
242+
104243 /// <summary>
105244 /// Converts this response message into a CloudEvent object, with the given extensions.
106245 /// </summary>
@@ -382,7 +521,7 @@ static CloudEvent ToCloudEventInternal(HttpResponseMessage httpResponseMessage,
382521 else
383522 {
384523 attributes [ name ] = headerValue ;
385- }
524+ }
386525 }
387526 }
388527
0 commit comments