Skip to content

Commit 8714f2e

Browse files
authored
Feature/hhvm 4.35 patch (#39)
* wip * updated * Update .hhconfig * changed dependency * Update .travis.yml * Update .travis.sh * Update README.md * added cors middleware
1 parent cfed5e2 commit 8714f2e

File tree

10 files changed

+197
-12
lines changed

10 files changed

+197
-12
lines changed

composer.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,16 @@
1919
"hhvm": "^4.35",
2020
"hhvm/hsl": "^4.0",
2121
"hhvm/hsl-experimental": "^4.25",
22-
"hhvm/hhvm-autoload": "^3.0.0",
22+
"hhvm/hhvm-autoload": "^3.0",
2323
"hhvm/type-assert": "^3.7",
2424
"hack-psr/psr7-http-message-hhi": "^1.0.0",
2525
"ytake/hungrr": "^0.9.0",
2626
"ytake/hhypermedia": "^0.5.0",
2727
"nazg/glue": "^1.4.0",
28-
"nazg/heredity": "^1.8.0",
28+
"nazg/heredity": "^1.9",
2929
"nazg/hcache": "^0.5.0",
30-
"nazg/http-server-request-handler": "^0.4.1",
31-
"nazg/http-executor": "^0.8.0",
30+
"nazg/http-server-request-handler": "^0.5",
31+
"nazg/http-executor": "^0.9",
3232
"facebook/hack-router": ">=0.17 <1.0",
3333
"facebook/hack-http-request-response-interfaces": "^0.2",
3434
"hack-logging/hack-logging": "^0.4.0"

src/Foundation/Application.hack

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class Application {
5050
public function __construct(
5151
private Container $container,
5252
private IO\ReadHandle $readHandle,
53-
private IO\WriteHandle $writeHandle,
53+
private IO\CloseableWriteHandle $writeHandle,
5454
) {}
5555

5656
public function build(ApplicationConfig $config): this {

src/Middleware/Dispatcher.hack

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*/
1616
namespace Nazg\Middleware;
1717

18-
use type HH\Lib\Experimental\IO\WriteHandle;
18+
use type HH\Lib\Experimental\IO\CloseableWriteHandle;
1919
use type Nazg\Heredity\AsyncHeredity;
2020
use type Nazg\Glue\Container;
2121
use type Nazg\Http\Server\AsyncMiddlewareInterface;
@@ -30,7 +30,7 @@ class Dispatcher extends AsyncHeredity {
3030

3131
<<__Override>>
3232
protected async function processorAsync(
33-
WriteHandle $writeHandle,
33+
CloseableWriteHandle $writeHandle,
3434
AsyncMiddlewareInterface $middleware,
3535
ServerRequestInterface $request
3636
): Awaitable<ResponseInterface> {

src/Middleware/LogExceptionMiddleware.hack

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace Nazg\Middleware;
1717

1818
use type HackLogging\Logger;
1919
use type HackLogging\LogLevel;
20-
use type HH\Lib\Experimental\IO\WriteHandle;
20+
use type HH\Lib\Experimental\IO\CloseableWriteHandle;
2121
use type Facebook\Experimental\Http\Message\ResponseInterface;
2222
use type Facebook\Experimental\Http\Message\ServerRequestInterface;
2323
use type Nazg\Http\Server\AsyncMiddlewareInterface;
@@ -30,7 +30,7 @@ class LogExceptionMiddleware implements AsyncMiddlewareInterface {
3030
) {}
3131

3232
public async function processAsync(
33-
WriteHandle $writeHandle,
33+
CloseableWriteHandle $writeHandle,
3434
ServerRequestInterface $request,
3535
AsyncRequestHandlerInterface $handler,
3636
): Awaitable<ResponseInterface> {
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/**
2+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
5+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
7+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
8+
* THE SOFTWARE.
9+
*
10+
* This software consists of voluntary contributions made by many individuals
11+
* and is licensed under the MIT license.
12+
*
13+
* Copyright (c) 2017-2020 Yuuki Takezawa
14+
*
15+
*/
16+
namespace Nazg\Middleware;
17+
18+
use type Facebook\HackRouter\HttpMethod;
19+
use type Facebook\Experimental\Http\Message\ResponseInterface;
20+
use type Facebook\Experimental\Http\Message\ServerRequestInterface;
21+
use type HH\Lib\Experimental\IO\CloseableWriteHandle;
22+
use type Nazg\Http\Server\AsyncMiddlewareInterface;
23+
use type Nazg\Http\Server\AsyncRequestHandlerInterface;
24+
use function implode;
25+
26+
type CorsSetting = shape(
27+
?'origin' => string,
28+
?'header' => string,
29+
'methods' => Vector<HttpMethod>,
30+
);
31+
32+
enum AccessControl : string as string {
33+
AllowOrigin = 'Access-Control-Allow-Origin';
34+
AllowHeaders = 'Access-Control-Allow-Headers';
35+
AllowMethods = 'Access-Control-Allow-Methods';
36+
}
37+
38+
class SimpleCorsMiddleware implements AsyncMiddlewareInterface {
39+
40+
protected string $allowOrigin = '*';
41+
protected string
42+
$allowHeaders = 'X-Requested-With, Content-Type, Accept, Origin, Authorization';
43+
protected Vector<HttpMethod>
44+
$allowMethods = Vector {
45+
HttpMethod::GET,
46+
HttpMethod::HEAD,
47+
HttpMethod::POST,
48+
};
49+
50+
public function __construct(protected CorsSetting $cors) {}
51+
52+
public async function processAsync(
53+
CloseableWriteHandle $writeHandle,
54+
ServerRequestInterface $request,
55+
AsyncRequestHandlerInterface $handler,
56+
): Awaitable<ResponseInterface> {
57+
$response = await $handler->handleAsync($writeHandle, $request);
58+
$origin = ($this->cors['origin']) ?? $this->allowOrigin;
59+
$header = ($this->cors['header']) ?? $this->allowHeaders;
60+
$methods =
61+
($this->cors['methods']->isEmpty())
62+
? $this->allowMethods
63+
: $this->cors['methods'];
64+
return
65+
$response->withHeader(AccessControl::AllowOrigin, vec[$origin])
66+
->withHeader(AccessControl::AllowHeaders, vec[$header])
67+
->withHeader(
68+
AccessControl::AllowMethods,
69+
vec[$this->implodeMethods($methods)],
70+
);
71+
}
72+
73+
<<__Rx>>
74+
protected function implodeMethods(Vector<HttpMethod> $methods): string {
75+
return implode(",", $methods);
76+
}
77+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
5+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
7+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
8+
* THE SOFTWARE.
9+
*
10+
* This software consists of voluntary contributions made by many individuals
11+
* and is licensed under the MIT license.
12+
*
13+
* Copyright (c) 2017-2020 Yuuki Takezawa
14+
*
15+
*/
16+
namespace Nazg\Middleware;
17+
18+
use type Facebook\HackRouter\HttpMethod;
19+
use type Nazg\Glue\Container;
20+
use type Nazg\Glue\ProviderInterface;
21+
22+
class SimpleCorsMiddlewareProvider implements ProviderInterface<SimpleCorsMiddleware> {
23+
24+
public function get(
25+
Container $container
26+
): SimpleCorsMiddleware {
27+
return new SimpleCorsMiddleware(shape(
28+
'methods' => Vector {
29+
HttpMethod::GET,
30+
HttpMethod::HEAD,
31+
HttpMethod::POST,
32+
},
33+
)
34+
);
35+
}
36+
}

tests/Logger/LoggerProviderTest.hack

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ final class LoggerProviderTest extends HackTest {
1414
$container->bind(ApplicationConfig::class)
1515
->to(ApplicationConfig::class);
1616
expect(() ==> $logger->get($container))
17-
->toThrow(\HH\Lib\Experimental\OS\NotFoundException::class);
17+
->toThrow(\HH\Lib\Experimental\OS\Exception::class);
1818
}
1919

2020
public function testShouldReturnLoggerInstance(): void {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
use type HH\Lib\Experimental\IO\CloseableWriteHandle;
2+
use type Facebook\Experimental\Http\Message\ResponseInterface;
3+
use type Facebook\Experimental\Http\Message\ServerRequestInterface;
4+
use type Nazg\Http\Server\AsyncMiddlewareInterface;
5+
use type Nazg\Http\Server\AsyncRequestHandlerInterface;
6+
7+
final class FakeActionMiddleware implements AsyncMiddlewareInterface {
8+
9+
public async function processAsync(
10+
CloseableWriteHandle $writeHandle,
11+
ServerRequestInterface $request,
12+
AsyncRequestHandlerInterface $handler,
13+
): Awaitable<ResponseInterface> {
14+
return await $handler->handleAsync($writeHandle, $request);
15+
}
16+
}

tests/Middleware/FakeThrowExceptionMiddleware.hack

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use type HH\Lib\Experimental\IO\WriteHandle;
1+
use type HH\Lib\Experimental\IO\CloseableWriteHandle;
22
use type Facebook\Experimental\Http\Message\ResponseInterface;
33
use type Facebook\Experimental\Http\Message\ServerRequestInterface;
44
use type Nazg\Http\Server\AsyncMiddlewareInterface;
@@ -7,7 +7,7 @@ use type Nazg\Http\Server\AsyncRequestHandlerInterface;
77
final class FakeThrowExceptionMiddleware implements AsyncMiddlewareInterface {
88

99
public async function processAsync(
10-
WriteHandle $writeHandle,
10+
CloseableWriteHandle $writeHandle,
1111
ServerRequestInterface $request,
1212
AsyncRequestHandlerInterface $handler,
1313
): Awaitable<ResponseInterface> {
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
use type HackLogging\Logger;
2+
use type Nazg\Glue\{Container, Scope, DependencyFactory};
3+
use type Nazg\Heredity\AsyncMiddlewareStack;
4+
use type Facebook\HackTest\HackTest;
5+
use type Ytake\Hungrr\ServerRequestFactory;
6+
use type Nazg\RequestHandler\AsyncFallbackHandler;
7+
use type Nazg\Foundation\ApplicationConfig;
8+
use namespace Nazg\Logger;
9+
use namespace Nazg\Middleware;
10+
use namespace HH\Lib\Experimental\IO;
11+
use function Facebook\FBExpect\expect;
12+
13+
final class SimpleCorsMiddlewareTest extends HackTest {
14+
15+
private function getDependency(): Container {
16+
$container = new Container(new DependencyFactory());
17+
$container->bind(Middleware\SimpleCorsMiddleware::class)
18+
->provider(new Middleware\SimpleCorsMiddlewareProvider());
19+
$container->bind(FakeThrowExceptionMiddleware::class)
20+
->to(FakeThrowExceptionMiddleware::class);
21+
$container->bind(FakeActionMiddleware::class)
22+
->to(FakeActionMiddleware::class);
23+
\HH\Asio\join($container->lockAsync());
24+
return $container;
25+
}
26+
27+
public async function testShouldReturnCorsHeader(): Awaitable<void> {
28+
$filename = __DIR__ . '/../storages/testing.log';
29+
list($read, $write) = IO\pipe_nd();
30+
$heredity = new Middleware\Dispatcher(
31+
new AsyncMiddlewareStack(
32+
vec[
33+
Middleware\SimpleCorsMiddleware::class,
34+
FakeActionMiddleware::class
35+
],
36+
new Middleware\GlueResolver($this->getDependency())
37+
),
38+
new AsyncFallbackHandler(),
39+
);
40+
$res = await $heredity->handleAsync(
41+
$write,
42+
ServerRequestFactory::fromGlobals($read)
43+
);
44+
$headers = $res->getHeaders();
45+
expect($headers)->toContainKey('Access-Control-Allow-Origin');
46+
expect($headers)->toContainKey('Access-Control-Allow-Headers');
47+
expect($headers)->toContainKey('Access-Control-Allow-Methods');
48+
49+
expect($headers['Access-Control-Allow-Origin'])
50+
->toBeSame(vec['*']);
51+
expect($headers['Access-Control-Allow-Headers'])
52+
->toBeSame(vec['X-Requested-With, Content-Type, Accept, Origin, Authorization']);
53+
expect($headers['Access-Control-Allow-Methods'])
54+
->toBeSame(vec['GET,HEAD,POST']);
55+
}
56+
}

0 commit comments

Comments
 (0)