@jaredwray/mockhttp 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -0
- package/dist/index.js +697 -143
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ type HttpBinOptions = {
|
|
|
7
7
|
requestInspection?: boolean;
|
|
8
8
|
responseInspection?: boolean;
|
|
9
9
|
statusCodes?: boolean;
|
|
10
|
+
responseFormats?: boolean;
|
|
10
11
|
cookies?: boolean;
|
|
11
12
|
anything?: boolean;
|
|
12
13
|
auth?: boolean;
|
|
@@ -155,6 +156,7 @@ declare class MockHttp extends Hookified {
|
|
|
155
156
|
* @param fastifyInstance - the server instance to register the routes on.
|
|
156
157
|
*/
|
|
157
158
|
registerResponseInspectionRoutes(fastifyInstance?: FastifyInstance): Promise<void>;
|
|
159
|
+
registerResponseFormatRoutes(fastifyInstance?: FastifyInstance): Promise<void>;
|
|
158
160
|
/**
|
|
159
161
|
* Register the redirect routes.
|
|
160
162
|
* @param fastifyInstance - the server instance to register the routes on.
|
package/dist/index.js
CHANGED
|
@@ -1296,156 +1296,114 @@ var userAgentRoute = /* @__PURE__ */ __name((fastify) => {
|
|
|
1296
1296
|
});
|
|
1297
1297
|
}, "userAgentRoute");
|
|
1298
1298
|
|
|
1299
|
-
// src/routes/response-
|
|
1300
|
-
|
|
1301
|
-
|
|
1299
|
+
// src/routes/response-formats/index.ts
|
|
1300
|
+
import { brotliCompressSync, deflateSync, gzipSync } from "zlib";
|
|
1301
|
+
var plainSchema = {
|
|
1302
|
+
description: "Returns random plain text content",
|
|
1302
1303
|
tags: [
|
|
1303
|
-
"Response
|
|
1304
|
+
"Response Formats"
|
|
1304
1305
|
],
|
|
1305
1306
|
response: {
|
|
1306
1307
|
200: {
|
|
1307
1308
|
type: "string",
|
|
1308
|
-
description: "
|
|
1309
|
-
},
|
|
1310
|
-
304: {
|
|
1311
|
-
type: "null",
|
|
1312
|
-
description: "Indicates the resource has not been modified."
|
|
1309
|
+
description: "Random plain text content"
|
|
1313
1310
|
}
|
|
1314
1311
|
}
|
|
1315
1312
|
};
|
|
1316
|
-
var
|
|
1317
|
-
description: "
|
|
1313
|
+
var textSchema = {
|
|
1314
|
+
description: "Returns random text content",
|
|
1318
1315
|
tags: [
|
|
1319
|
-
"Response
|
|
1316
|
+
"Response Formats"
|
|
1320
1317
|
],
|
|
1321
|
-
params: {
|
|
1322
|
-
type: "object",
|
|
1323
|
-
properties: {
|
|
1324
|
-
value: {
|
|
1325
|
-
type: "integer",
|
|
1326
|
-
description: "Number of seconds to cache the resource."
|
|
1327
|
-
}
|
|
1328
|
-
},
|
|
1329
|
-
required: [
|
|
1330
|
-
"value"
|
|
1331
|
-
]
|
|
1332
|
-
},
|
|
1333
1318
|
response: {
|
|
1334
1319
|
200: {
|
|
1335
1320
|
type: "string",
|
|
1336
|
-
description: "
|
|
1321
|
+
description: "Random text content"
|
|
1337
1322
|
}
|
|
1338
1323
|
}
|
|
1339
1324
|
};
|
|
1340
|
-
var
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1325
|
+
var htmlSchema = {
|
|
1326
|
+
description: "Returns random HTML content",
|
|
1327
|
+
tags: [
|
|
1328
|
+
"Response Formats"
|
|
1329
|
+
],
|
|
1330
|
+
response: {
|
|
1331
|
+
200: {
|
|
1332
|
+
type: "string",
|
|
1333
|
+
description: "Random HTML content"
|
|
1349
1334
|
}
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
}, async (request, reply) => {
|
|
1355
|
-
const { value } = request.params;
|
|
1356
|
-
await reply.header("Cache-Control", `max-age=${value}`).send(`Cache-Control set for ${value} seconds.`);
|
|
1357
|
-
});
|
|
1358
|
-
}, "cacheRoutes");
|
|
1359
|
-
|
|
1360
|
-
// src/routes/response-inspection/etag.ts
|
|
1361
|
-
var etagSchema = {
|
|
1362
|
-
description: "Handles ETag-based conditional requests.",
|
|
1335
|
+
}
|
|
1336
|
+
};
|
|
1337
|
+
var xmlSchema = {
|
|
1338
|
+
description: "Returns random XML content",
|
|
1363
1339
|
tags: [
|
|
1364
|
-
"Response
|
|
1340
|
+
"Response Formats"
|
|
1365
1341
|
],
|
|
1366
|
-
params: {
|
|
1367
|
-
type: "object",
|
|
1368
|
-
properties: {
|
|
1369
|
-
etag: {
|
|
1370
|
-
type: "string",
|
|
1371
|
-
description: "The ETag value for the resource."
|
|
1372
|
-
}
|
|
1373
|
-
},
|
|
1374
|
-
required: [
|
|
1375
|
-
"etag"
|
|
1376
|
-
]
|
|
1377
|
-
},
|
|
1378
1342
|
response: {
|
|
1379
1343
|
200: {
|
|
1380
1344
|
type: "string",
|
|
1381
|
-
description: "
|
|
1382
|
-
},
|
|
1383
|
-
304: {
|
|
1384
|
-
type: "null",
|
|
1385
|
-
description: "Indicates the resource has not been modified."
|
|
1386
|
-
},
|
|
1387
|
-
412: {
|
|
1388
|
-
type: "null",
|
|
1389
|
-
description: "Indicates a precondition failed due to mismatched ETag."
|
|
1345
|
+
description: "Random XML content"
|
|
1390
1346
|
}
|
|
1391
1347
|
}
|
|
1392
1348
|
};
|
|
1393
|
-
var
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1349
|
+
var jsonSchema = {
|
|
1350
|
+
description: "Returns random JSON content",
|
|
1351
|
+
tags: [
|
|
1352
|
+
"Response Formats"
|
|
1353
|
+
],
|
|
1354
|
+
response: {
|
|
1355
|
+
200: {
|
|
1356
|
+
type: "object",
|
|
1357
|
+
description: "Random JSON content",
|
|
1358
|
+
additionalProperties: true
|
|
1403
1359
|
}
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1360
|
+
}
|
|
1361
|
+
};
|
|
1362
|
+
var denySchema = {
|
|
1363
|
+
description: "Returns page denied by robots.txt rules",
|
|
1364
|
+
tags: [
|
|
1365
|
+
"Response Formats"
|
|
1366
|
+
],
|
|
1367
|
+
response: {
|
|
1368
|
+
403: {
|
|
1369
|
+
type: "string",
|
|
1370
|
+
description: "Page denied by robots.txt rules"
|
|
1407
1371
|
}
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
// src/routes/response-inspection/plain.ts
|
|
1413
|
-
var plainSchema = {
|
|
1414
|
-
description: "Returns random plain text content",
|
|
1372
|
+
}
|
|
1373
|
+
};
|
|
1374
|
+
var gzipSchema = {
|
|
1375
|
+
description: "Returns GZip-encoded data",
|
|
1415
1376
|
tags: [
|
|
1416
|
-
"Response
|
|
1377
|
+
"Response Formats"
|
|
1417
1378
|
],
|
|
1418
|
-
// @ts-expect-error
|
|
1419
1379
|
response: {
|
|
1420
1380
|
200: {
|
|
1421
1381
|
type: "string",
|
|
1422
|
-
description: "
|
|
1382
|
+
description: "GZip-encoded content"
|
|
1423
1383
|
}
|
|
1424
1384
|
}
|
|
1425
1385
|
};
|
|
1426
|
-
var
|
|
1427
|
-
description: "Returns
|
|
1386
|
+
var deflateSchema = {
|
|
1387
|
+
description: "Returns Deflate-encoded data",
|
|
1428
1388
|
tags: [
|
|
1429
|
-
"Response
|
|
1389
|
+
"Response Formats"
|
|
1430
1390
|
],
|
|
1431
|
-
// @ts-expect-error
|
|
1432
1391
|
response: {
|
|
1433
1392
|
200: {
|
|
1434
1393
|
type: "string",
|
|
1435
|
-
description: "
|
|
1394
|
+
description: "Deflate-encoded content"
|
|
1436
1395
|
}
|
|
1437
1396
|
}
|
|
1438
1397
|
};
|
|
1439
|
-
var
|
|
1440
|
-
description: "Returns
|
|
1398
|
+
var brotliSchema = {
|
|
1399
|
+
description: "Returns Brotli-encoded data",
|
|
1441
1400
|
tags: [
|
|
1442
|
-
"Response
|
|
1401
|
+
"Response Formats"
|
|
1443
1402
|
],
|
|
1444
|
-
// @ts-expect-error
|
|
1445
1403
|
response: {
|
|
1446
1404
|
200: {
|
|
1447
1405
|
type: "string",
|
|
1448
|
-
description: "
|
|
1406
|
+
description: "Brotli-encoded content"
|
|
1449
1407
|
}
|
|
1450
1408
|
}
|
|
1451
1409
|
};
|
|
@@ -1547,47 +1505,636 @@ var randomHtmlContent = [
|
|
|
1547
1505
|
</body>
|
|
1548
1506
|
</html>`
|
|
1549
1507
|
];
|
|
1550
|
-
var
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1508
|
+
var randomXmlContent = [
|
|
1509
|
+
`<?xml version="1.0" encoding="UTF-8"?>
|
|
1510
|
+
<root>
|
|
1511
|
+
<message>Hello from MockHTTP</message>
|
|
1512
|
+
<timestamp>${(/* @__PURE__ */ new Date()).toISOString()}</timestamp>
|
|
1513
|
+
<status>success</status>
|
|
1514
|
+
</root>`,
|
|
1515
|
+
`<?xml version="1.0" encoding="UTF-8"?>
|
|
1516
|
+
<book>
|
|
1517
|
+
<title>The Great Gatsby</title>
|
|
1518
|
+
<author>F. Scott Fitzgerald</author>
|
|
1519
|
+
<year>1925</year>
|
|
1520
|
+
<publisher>Charles Scribner's Sons</publisher>
|
|
1521
|
+
<isbn>978-0-7432-7356-5</isbn>
|
|
1522
|
+
</book>`,
|
|
1523
|
+
`<?xml version="1.0" encoding="UTF-8"?>
|
|
1524
|
+
<users>
|
|
1525
|
+
<user id="1">
|
|
1526
|
+
<name>John Doe</name>
|
|
1527
|
+
<email>john@example.com</email>
|
|
1528
|
+
<role>admin</role>
|
|
1529
|
+
</user>
|
|
1530
|
+
<user id="2">
|
|
1531
|
+
<name>Jane Smith</name>
|
|
1532
|
+
<email>jane@example.com</email>
|
|
1533
|
+
<role>user</role>
|
|
1534
|
+
</user>
|
|
1535
|
+
</users>`,
|
|
1536
|
+
`<?xml version="1.0" encoding="UTF-8"?>
|
|
1537
|
+
<product>
|
|
1538
|
+
<id>12345</id>
|
|
1539
|
+
<name>Wireless Mouse</name>
|
|
1540
|
+
<description>Ergonomic wireless mouse with 3-year battery life</description>
|
|
1541
|
+
<price currency="USD">29.99</price>
|
|
1542
|
+
<stock>150</stock>
|
|
1543
|
+
<category>Electronics</category>
|
|
1544
|
+
</product>`,
|
|
1545
|
+
`<?xml version="1.0" encoding="UTF-8"?>
|
|
1546
|
+
<rss version="2.0">
|
|
1547
|
+
<channel>
|
|
1548
|
+
<title>Mock RSS Feed</title>
|
|
1549
|
+
<link>http://example.com/rss</link>
|
|
1550
|
+
<description>Sample RSS feed from MockHTTP</description>
|
|
1551
|
+
<item>
|
|
1552
|
+
<title>First Article</title>
|
|
1553
|
+
<link>http://example.com/article1</link>
|
|
1554
|
+
<description>This is the first article in our feed</description>
|
|
1555
|
+
<pubDate>${(/* @__PURE__ */ new Date()).toUTCString()}</pubDate>
|
|
1556
|
+
</item>
|
|
1557
|
+
</channel>
|
|
1558
|
+
</rss>`
|
|
1559
|
+
];
|
|
1560
|
+
var randomJsonContent = [
|
|
1561
|
+
() => ({
|
|
1562
|
+
message: "Hello from MockHTTP",
|
|
1563
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1564
|
+
status: "success",
|
|
1565
|
+
code: 200
|
|
1566
|
+
}),
|
|
1567
|
+
() => ({
|
|
1568
|
+
user: {
|
|
1569
|
+
id: 1,
|
|
1570
|
+
name: "John Doe",
|
|
1571
|
+
email: "john@example.com",
|
|
1572
|
+
role: "admin",
|
|
1573
|
+
createdAt: "2024-01-15T10:30:00Z"
|
|
1574
|
+
},
|
|
1575
|
+
permissions: [
|
|
1576
|
+
"read",
|
|
1577
|
+
"write",
|
|
1578
|
+
"delete"
|
|
1579
|
+
]
|
|
1580
|
+
}),
|
|
1581
|
+
() => ({
|
|
1582
|
+
products: [
|
|
1583
|
+
{
|
|
1584
|
+
id: 101,
|
|
1585
|
+
name: "Laptop",
|
|
1586
|
+
price: 999.99,
|
|
1587
|
+
stock: 50
|
|
1588
|
+
},
|
|
1589
|
+
{
|
|
1590
|
+
id: 102,
|
|
1591
|
+
name: "Mouse",
|
|
1592
|
+
price: 29.99,
|
|
1593
|
+
stock: 200
|
|
1594
|
+
}
|
|
1595
|
+
],
|
|
1596
|
+
total: 2,
|
|
1597
|
+
page: 1
|
|
1598
|
+
}),
|
|
1599
|
+
() => ({
|
|
1600
|
+
config: {
|
|
1601
|
+
theme: "dark",
|
|
1602
|
+
language: "en",
|
|
1603
|
+
notifications: {
|
|
1604
|
+
email: true,
|
|
1605
|
+
push: false,
|
|
1606
|
+
sms: false
|
|
1607
|
+
},
|
|
1608
|
+
privacy: {
|
|
1609
|
+
profile: "public",
|
|
1610
|
+
activity: "friends"
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
}),
|
|
1614
|
+
() => ({
|
|
1615
|
+
metrics: {
|
|
1616
|
+
cpu: 45.2,
|
|
1617
|
+
memory: 78.5,
|
|
1618
|
+
disk: 62.3,
|
|
1619
|
+
network: {
|
|
1620
|
+
inbound: "1.2MB/s",
|
|
1621
|
+
outbound: "0.8MB/s"
|
|
1622
|
+
},
|
|
1623
|
+
uptime: "15 days",
|
|
1624
|
+
services: [
|
|
1625
|
+
{
|
|
1626
|
+
name: "api",
|
|
1627
|
+
status: "healthy"
|
|
1628
|
+
},
|
|
1629
|
+
{
|
|
1630
|
+
name: "database",
|
|
1631
|
+
status: "healthy"
|
|
1632
|
+
},
|
|
1633
|
+
{
|
|
1634
|
+
name: "cache",
|
|
1635
|
+
status: "warning"
|
|
1636
|
+
}
|
|
1637
|
+
]
|
|
1638
|
+
}
|
|
1639
|
+
})
|
|
1640
|
+
];
|
|
1641
|
+
var responseFormatRoutes = /* @__PURE__ */ __name((fastify) => {
|
|
1642
|
+
const plainHandler = /* @__PURE__ */ __name(async (_request, reply) => {
|
|
1643
|
+
const randomIndex = Math.floor(Math.random() * randomTexts.length);
|
|
1644
|
+
const text = randomTexts[randomIndex];
|
|
1645
|
+
reply.type("text/plain");
|
|
1646
|
+
return text;
|
|
1647
|
+
}, "plainHandler");
|
|
1648
|
+
fastify.get("/plain", {
|
|
1649
|
+
schema: plainSchema
|
|
1650
|
+
}, plainHandler);
|
|
1651
|
+
fastify.post("/plain", {
|
|
1652
|
+
schema: plainSchema
|
|
1653
|
+
}, plainHandler);
|
|
1654
|
+
fastify.put("/plain", {
|
|
1655
|
+
schema: plainSchema
|
|
1656
|
+
}, plainHandler);
|
|
1657
|
+
fastify.patch("/plain", {
|
|
1658
|
+
schema: plainSchema
|
|
1659
|
+
}, plainHandler);
|
|
1660
|
+
fastify.delete("/plain", {
|
|
1661
|
+
schema: plainSchema
|
|
1662
|
+
}, plainHandler);
|
|
1663
|
+
const textHandler = /* @__PURE__ */ __name(async (_request, reply) => {
|
|
1664
|
+
const randomIndex = Math.floor(Math.random() * randomTexts.length);
|
|
1665
|
+
const text = randomTexts[randomIndex];
|
|
1666
|
+
reply.type("text/plain");
|
|
1667
|
+
return text;
|
|
1668
|
+
}, "textHandler");
|
|
1669
|
+
fastify.get("/text", {
|
|
1670
|
+
schema: textSchema
|
|
1671
|
+
}, textHandler);
|
|
1672
|
+
fastify.post("/text", {
|
|
1673
|
+
schema: textSchema
|
|
1674
|
+
}, textHandler);
|
|
1675
|
+
fastify.put("/text", {
|
|
1676
|
+
schema: textSchema
|
|
1677
|
+
}, textHandler);
|
|
1678
|
+
fastify.patch("/text", {
|
|
1679
|
+
schema: textSchema
|
|
1680
|
+
}, textHandler);
|
|
1681
|
+
fastify.delete("/text", {
|
|
1682
|
+
schema: textSchema
|
|
1683
|
+
}, textHandler);
|
|
1684
|
+
const htmlHandler = /* @__PURE__ */ __name(async (_request, reply) => {
|
|
1685
|
+
const randomIndex = Math.floor(Math.random() * randomHtmlContent.length);
|
|
1686
|
+
const html = randomHtmlContent[randomIndex];
|
|
1687
|
+
reply.type("text/html");
|
|
1688
|
+
return html;
|
|
1689
|
+
}, "htmlHandler");
|
|
1690
|
+
fastify.get("/html", {
|
|
1691
|
+
schema: htmlSchema
|
|
1692
|
+
}, htmlHandler);
|
|
1693
|
+
fastify.post("/html", {
|
|
1694
|
+
schema: htmlSchema
|
|
1695
|
+
}, htmlHandler);
|
|
1696
|
+
fastify.put("/html", {
|
|
1697
|
+
schema: htmlSchema
|
|
1698
|
+
}, htmlHandler);
|
|
1699
|
+
fastify.patch("/html", {
|
|
1700
|
+
schema: htmlSchema
|
|
1701
|
+
}, htmlHandler);
|
|
1702
|
+
fastify.delete("/html", {
|
|
1703
|
+
schema: htmlSchema
|
|
1704
|
+
}, htmlHandler);
|
|
1705
|
+
const xmlHandler = /* @__PURE__ */ __name(async (_request, reply) => {
|
|
1706
|
+
const randomIndex = Math.floor(Math.random() * randomXmlContent.length);
|
|
1707
|
+
const xml = randomXmlContent[randomIndex];
|
|
1708
|
+
reply.type("application/xml");
|
|
1709
|
+
return xml;
|
|
1710
|
+
}, "xmlHandler");
|
|
1711
|
+
fastify.get("/xml", {
|
|
1712
|
+
schema: xmlSchema
|
|
1713
|
+
}, xmlHandler);
|
|
1714
|
+
fastify.post("/xml", {
|
|
1715
|
+
schema: xmlSchema
|
|
1716
|
+
}, xmlHandler);
|
|
1717
|
+
fastify.put("/xml", {
|
|
1718
|
+
schema: xmlSchema
|
|
1719
|
+
}, xmlHandler);
|
|
1720
|
+
fastify.patch("/xml", {
|
|
1721
|
+
schema: xmlSchema
|
|
1722
|
+
}, xmlHandler);
|
|
1723
|
+
fastify.delete("/xml", {
|
|
1724
|
+
schema: xmlSchema
|
|
1725
|
+
}, xmlHandler);
|
|
1726
|
+
const jsonHandler = /* @__PURE__ */ __name(async (_request, reply) => {
|
|
1727
|
+
const randomIndex = Math.floor(Math.random() * randomJsonContent.length);
|
|
1728
|
+
const jsonGenerator = randomJsonContent[randomIndex];
|
|
1729
|
+
const json = jsonGenerator();
|
|
1730
|
+
reply.type("application/json");
|
|
1731
|
+
return json;
|
|
1732
|
+
}, "jsonHandler");
|
|
1733
|
+
fastify.get("/json", {
|
|
1734
|
+
schema: jsonSchema
|
|
1735
|
+
}, jsonHandler);
|
|
1736
|
+
fastify.post("/json", {
|
|
1737
|
+
schema: jsonSchema
|
|
1738
|
+
}, jsonHandler);
|
|
1739
|
+
fastify.put("/json", {
|
|
1740
|
+
schema: jsonSchema
|
|
1741
|
+
}, jsonHandler);
|
|
1742
|
+
fastify.patch("/json", {
|
|
1743
|
+
schema: jsonSchema
|
|
1744
|
+
}, jsonHandler);
|
|
1745
|
+
fastify.delete("/json", {
|
|
1746
|
+
schema: jsonSchema
|
|
1747
|
+
}, jsonHandler);
|
|
1748
|
+
const denyHandler = /* @__PURE__ */ __name(async (_request, reply) => {
|
|
1749
|
+
const denyMessages = [
|
|
1750
|
+
`<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
|
|
1751
|
+
<html><head>
|
|
1752
|
+
<title>403 Forbidden</title>
|
|
1753
|
+
</head><body>
|
|
1754
|
+
<h1>Forbidden</h1>
|
|
1755
|
+
<p>Access denied by robots.txt rules.</p>
|
|
1756
|
+
<p>The requested resource is disallowed by robots.txt.</p>
|
|
1757
|
+
</body></html>`,
|
|
1758
|
+
`<!DOCTYPE html>
|
|
1759
|
+
<html lang="en">
|
|
1760
|
+
<head>
|
|
1761
|
+
<meta charset="UTF-8">
|
|
1762
|
+
<title>403 - Access Denied</title>
|
|
1763
|
+
</head>
|
|
1764
|
+
<body>
|
|
1765
|
+
<h1>403 Forbidden</h1>
|
|
1766
|
+
<p>This page is blocked by robots.txt rules.</p>
|
|
1767
|
+
<p>User-agent: *<br>Disallow: ${_request.url}</p>
|
|
1768
|
+
</body>
|
|
1769
|
+
</html>`,
|
|
1770
|
+
`<!DOCTYPE html>
|
|
1771
|
+
<html>
|
|
1772
|
+
<head>
|
|
1773
|
+
<title>403 - Access Denied</title>
|
|
1774
|
+
<style>body { font-family: Arial, sans-serif; margin: 40px; }</style>
|
|
1775
|
+
</head>
|
|
1776
|
+
<body>
|
|
1777
|
+
<h2>403 - Access Denied by robots.txt</h2>
|
|
1778
|
+
<p>The robots.txt file prevents access to this resource.</p>
|
|
1779
|
+
<hr>
|
|
1780
|
+
<small>MockHTTP Server</small>
|
|
1781
|
+
</body>
|
|
1782
|
+
</html>`
|
|
1783
|
+
];
|
|
1784
|
+
const randomIndex = Math.floor(Math.random() * denyMessages.length);
|
|
1785
|
+
const html = denyMessages[randomIndex];
|
|
1786
|
+
reply.code(403);
|
|
1787
|
+
reply.type("text/html");
|
|
1788
|
+
return html;
|
|
1789
|
+
}, "denyHandler");
|
|
1790
|
+
fastify.get("/deny", {
|
|
1791
|
+
schema: denySchema
|
|
1792
|
+
}, denyHandler);
|
|
1793
|
+
fastify.post("/deny", {
|
|
1794
|
+
schema: denySchema
|
|
1795
|
+
}, denyHandler);
|
|
1796
|
+
fastify.put("/deny", {
|
|
1797
|
+
schema: denySchema
|
|
1798
|
+
}, denyHandler);
|
|
1799
|
+
fastify.patch("/deny", {
|
|
1800
|
+
schema: denySchema
|
|
1801
|
+
}, denyHandler);
|
|
1802
|
+
fastify.delete("/deny", {
|
|
1803
|
+
schema: denySchema
|
|
1804
|
+
}, denyHandler);
|
|
1805
|
+
const gzipHandler = /* @__PURE__ */ __name(async (_request, reply) => {
|
|
1806
|
+
const sampleData = [
|
|
1807
|
+
{
|
|
1808
|
+
message: "This is GZip compressed data from MockHTTP",
|
|
1809
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1810
|
+
compression: "gzip",
|
|
1811
|
+
originalSize: 0,
|
|
1812
|
+
compressedSize: 0
|
|
1813
|
+
},
|
|
1814
|
+
{
|
|
1815
|
+
title: "Sample Document",
|
|
1816
|
+
content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. ".repeat(50),
|
|
1817
|
+
metadata: {
|
|
1818
|
+
author: "MockHTTP Server",
|
|
1819
|
+
format: "gzip",
|
|
1820
|
+
version: "1.0"
|
|
1821
|
+
}
|
|
1822
|
+
},
|
|
1823
|
+
{
|
|
1824
|
+
data: Array.from({
|
|
1825
|
+
length: 100
|
|
1826
|
+
}, (_, i) => ({
|
|
1827
|
+
id: i + 1,
|
|
1828
|
+
value: `Item ${i + 1}`,
|
|
1829
|
+
description: `This is item number ${i + 1} in the dataset`
|
|
1830
|
+
})),
|
|
1831
|
+
info: "Large dataset compressed with GZip"
|
|
1832
|
+
}
|
|
1833
|
+
];
|
|
1834
|
+
const randomIndex = Math.floor(Math.random() * sampleData.length);
|
|
1835
|
+
const data = sampleData[randomIndex];
|
|
1836
|
+
const jsonString = JSON.stringify(data);
|
|
1837
|
+
if (data.originalSize !== void 0) {
|
|
1838
|
+
data.originalSize = Buffer.byteLength(jsonString);
|
|
1839
|
+
}
|
|
1840
|
+
const compressed = gzipSync(jsonString);
|
|
1841
|
+
if (data.compressedSize !== void 0) {
|
|
1842
|
+
const updatedData = {
|
|
1843
|
+
...data,
|
|
1844
|
+
compressedSize: compressed.length
|
|
1845
|
+
};
|
|
1846
|
+
const updatedJsonString = JSON.stringify(updatedData);
|
|
1847
|
+
const updatedCompressed = gzipSync(updatedJsonString);
|
|
1848
|
+
reply.header("Content-Encoding", "gzip");
|
|
1849
|
+
reply.header("Content-Type", "application/json");
|
|
1850
|
+
reply.type("application/octet-stream");
|
|
1851
|
+
return updatedCompressed;
|
|
1852
|
+
}
|
|
1853
|
+
reply.header("Content-Encoding", "gzip");
|
|
1854
|
+
reply.header("Content-Type", "application/json");
|
|
1855
|
+
reply.type("application/octet-stream");
|
|
1856
|
+
return compressed;
|
|
1857
|
+
}, "gzipHandler");
|
|
1858
|
+
fastify.get("/gzip", {
|
|
1859
|
+
schema: gzipSchema
|
|
1860
|
+
}, gzipHandler);
|
|
1861
|
+
fastify.post("/gzip", {
|
|
1862
|
+
schema: gzipSchema
|
|
1863
|
+
}, gzipHandler);
|
|
1864
|
+
fastify.put("/gzip", {
|
|
1865
|
+
schema: gzipSchema
|
|
1866
|
+
}, gzipHandler);
|
|
1867
|
+
fastify.patch("/gzip", {
|
|
1868
|
+
schema: gzipSchema
|
|
1869
|
+
}, gzipHandler);
|
|
1870
|
+
fastify.delete("/gzip", {
|
|
1871
|
+
schema: gzipSchema
|
|
1872
|
+
}, gzipHandler);
|
|
1873
|
+
const deflateHandler = /* @__PURE__ */ __name(async (_request, reply) => {
|
|
1874
|
+
const sampleData = [
|
|
1875
|
+
{
|
|
1876
|
+
message: "This is Deflate compressed data from MockHTTP",
|
|
1877
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1878
|
+
compression: "deflate",
|
|
1879
|
+
originalSize: 0,
|
|
1880
|
+
compressedSize: 0
|
|
1881
|
+
},
|
|
1882
|
+
{
|
|
1883
|
+
title: "Deflate Compressed Document",
|
|
1884
|
+
content: "The deflate algorithm is used for compression. ".repeat(40),
|
|
1885
|
+
details: {
|
|
1886
|
+
algorithm: "DEFLATE",
|
|
1887
|
+
method: "zlib deflate",
|
|
1888
|
+
server: "MockHTTP"
|
|
1889
|
+
}
|
|
1890
|
+
},
|
|
1891
|
+
{
|
|
1892
|
+
items: Array.from({
|
|
1893
|
+
length: 50
|
|
1894
|
+
}, (_, i) => ({
|
|
1895
|
+
index: i,
|
|
1896
|
+
name: `Entry ${i}`,
|
|
1897
|
+
data: `This is test data for entry number ${i}`,
|
|
1898
|
+
timestamp: new Date(Date.now() - i * 1e6).toISOString()
|
|
1899
|
+
})),
|
|
1900
|
+
metadata: {
|
|
1901
|
+
compression: "deflate",
|
|
1902
|
+
count: 50
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
];
|
|
1906
|
+
const randomIndex = Math.floor(Math.random() * sampleData.length);
|
|
1907
|
+
const data = sampleData[randomIndex];
|
|
1908
|
+
const jsonString = JSON.stringify(data);
|
|
1909
|
+
if (data.originalSize !== void 0) {
|
|
1910
|
+
data.originalSize = Buffer.byteLength(jsonString);
|
|
1911
|
+
}
|
|
1912
|
+
const compressed = deflateSync(jsonString);
|
|
1913
|
+
if (data.compressedSize !== void 0) {
|
|
1914
|
+
const updatedData = {
|
|
1915
|
+
...data,
|
|
1916
|
+
compressedSize: compressed.length
|
|
1917
|
+
};
|
|
1918
|
+
const updatedJsonString = JSON.stringify(updatedData);
|
|
1919
|
+
const updatedCompressed = deflateSync(updatedJsonString);
|
|
1920
|
+
reply.header("Content-Encoding", "deflate");
|
|
1921
|
+
reply.header("Content-Type", "application/json");
|
|
1922
|
+
reply.type("application/octet-stream");
|
|
1923
|
+
return updatedCompressed;
|
|
1924
|
+
}
|
|
1925
|
+
reply.header("Content-Encoding", "deflate");
|
|
1926
|
+
reply.header("Content-Type", "application/json");
|
|
1927
|
+
reply.type("application/octet-stream");
|
|
1928
|
+
return compressed;
|
|
1929
|
+
}, "deflateHandler");
|
|
1930
|
+
fastify.get("/deflate", {
|
|
1931
|
+
schema: deflateSchema
|
|
1932
|
+
}, deflateHandler);
|
|
1933
|
+
fastify.post("/deflate", {
|
|
1934
|
+
schema: deflateSchema
|
|
1935
|
+
}, deflateHandler);
|
|
1936
|
+
fastify.put("/deflate", {
|
|
1937
|
+
schema: deflateSchema
|
|
1938
|
+
}, deflateHandler);
|
|
1939
|
+
fastify.patch("/deflate", {
|
|
1940
|
+
schema: deflateSchema
|
|
1941
|
+
}, deflateHandler);
|
|
1942
|
+
fastify.delete("/deflate", {
|
|
1943
|
+
schema: deflateSchema
|
|
1944
|
+
}, deflateHandler);
|
|
1945
|
+
const brotliHandler = /* @__PURE__ */ __name(async (_request, reply) => {
|
|
1946
|
+
const sampleData = [
|
|
1947
|
+
{
|
|
1948
|
+
message: "This is Brotli compressed data from MockHTTP",
|
|
1949
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1950
|
+
compression: "br",
|
|
1951
|
+
algorithm: "Brotli",
|
|
1952
|
+
originalSize: 0,
|
|
1953
|
+
compressedSize: 0
|
|
1954
|
+
},
|
|
1955
|
+
{
|
|
1956
|
+
title: "Brotli Compression Example",
|
|
1957
|
+
description: "Brotli is a generic-purpose lossless compression algorithm that compresses data using a combination of a modern variant of the LZ77 algorithm, Huffman coding and 2nd order context modeling.",
|
|
1958
|
+
content: "Brotli compression typically achieves 20-26% better compression ratios than gzip. ".repeat(10),
|
|
1959
|
+
metadata: {
|
|
1960
|
+
encoding: "br",
|
|
1961
|
+
quality: 11,
|
|
1962
|
+
server: "MockHTTP"
|
|
1963
|
+
}
|
|
1964
|
+
},
|
|
1965
|
+
{
|
|
1966
|
+
benchmark: {
|
|
1967
|
+
title: "Compression Benchmark Data",
|
|
1968
|
+
results: Array.from({
|
|
1969
|
+
length: 75
|
|
1970
|
+
}, (_, i) => ({
|
|
1971
|
+
id: `test-${i}`,
|
|
1972
|
+
name: `Benchmark Test ${i}`,
|
|
1973
|
+
value: Math.random() * 1e3,
|
|
1974
|
+
unit: "ms",
|
|
1975
|
+
timestamp: new Date(Date.now() - i * 6e4).toISOString()
|
|
1976
|
+
})),
|
|
1977
|
+
summary: {
|
|
1978
|
+
compression: "brotli",
|
|
1979
|
+
totalTests: 75,
|
|
1980
|
+
encoding: "br"
|
|
1981
|
+
}
|
|
1982
|
+
}
|
|
1983
|
+
}
|
|
1984
|
+
];
|
|
1985
|
+
const randomIndex = Math.floor(Math.random() * sampleData.length);
|
|
1986
|
+
const data = sampleData[randomIndex];
|
|
1987
|
+
const jsonString = JSON.stringify(data);
|
|
1988
|
+
if (data.originalSize !== void 0) {
|
|
1989
|
+
data.originalSize = Buffer.byteLength(jsonString);
|
|
1990
|
+
}
|
|
1991
|
+
const compressed = brotliCompressSync(jsonString);
|
|
1992
|
+
if (data.compressedSize !== void 0) {
|
|
1993
|
+
const updatedData = {
|
|
1994
|
+
...data,
|
|
1995
|
+
compressedSize: compressed.length
|
|
1996
|
+
};
|
|
1997
|
+
const updatedJsonString = JSON.stringify(updatedData);
|
|
1998
|
+
const updatedCompressed = brotliCompressSync(updatedJsonString);
|
|
1999
|
+
reply.header("Content-Encoding", "br");
|
|
2000
|
+
reply.header("Content-Type", "application/json");
|
|
2001
|
+
reply.type("application/octet-stream");
|
|
2002
|
+
return updatedCompressed;
|
|
2003
|
+
}
|
|
2004
|
+
reply.header("Content-Encoding", "br");
|
|
2005
|
+
reply.header("Content-Type", "application/json");
|
|
2006
|
+
reply.type("application/octet-stream");
|
|
2007
|
+
return compressed;
|
|
2008
|
+
}, "brotliHandler");
|
|
2009
|
+
fastify.get("/brotli", {
|
|
2010
|
+
schema: brotliSchema
|
|
2011
|
+
}, brotliHandler);
|
|
2012
|
+
fastify.post("/brotli", {
|
|
2013
|
+
schema: brotliSchema
|
|
2014
|
+
}, brotliHandler);
|
|
2015
|
+
fastify.put("/brotli", {
|
|
2016
|
+
schema: brotliSchema
|
|
2017
|
+
}, brotliHandler);
|
|
2018
|
+
fastify.patch("/brotli", {
|
|
2019
|
+
schema: brotliSchema
|
|
2020
|
+
}, brotliHandler);
|
|
2021
|
+
fastify.delete("/brotli", {
|
|
2022
|
+
schema: brotliSchema
|
|
2023
|
+
}, brotliHandler);
|
|
2024
|
+
}, "responseFormatRoutes");
|
|
2025
|
+
|
|
2026
|
+
// src/routes/response-inspection/cache.ts
|
|
2027
|
+
var cacheGetSchema = {
|
|
2028
|
+
description: "Handles cache validation and retrieval.",
|
|
2029
|
+
tags: [
|
|
2030
|
+
"Response Inspection"
|
|
2031
|
+
],
|
|
2032
|
+
response: {
|
|
2033
|
+
200: {
|
|
2034
|
+
type: "string",
|
|
2035
|
+
description: "The cached content or resource."
|
|
2036
|
+
},
|
|
2037
|
+
304: {
|
|
2038
|
+
type: "null",
|
|
2039
|
+
description: "Indicates the resource has not been modified."
|
|
2040
|
+
}
|
|
2041
|
+
}
|
|
2042
|
+
};
|
|
2043
|
+
var cacheSetSchema = {
|
|
2044
|
+
description: "Sets a Cache-Control header for n seconds.",
|
|
2045
|
+
tags: [
|
|
2046
|
+
"Response Inspection"
|
|
2047
|
+
],
|
|
2048
|
+
params: {
|
|
2049
|
+
type: "object",
|
|
2050
|
+
properties: {
|
|
2051
|
+
value: {
|
|
2052
|
+
type: "integer",
|
|
2053
|
+
description: "Number of seconds to cache the resource."
|
|
2054
|
+
}
|
|
2055
|
+
},
|
|
2056
|
+
required: [
|
|
2057
|
+
"value"
|
|
2058
|
+
]
|
|
2059
|
+
},
|
|
2060
|
+
response: {
|
|
2061
|
+
200: {
|
|
2062
|
+
type: "string",
|
|
2063
|
+
description: "Confirmation message for setting cache."
|
|
2064
|
+
}
|
|
2065
|
+
}
|
|
2066
|
+
};
|
|
2067
|
+
var cacheRoutes = /* @__PURE__ */ __name((fastify) => {
|
|
2068
|
+
fastify.get("/cache", {
|
|
2069
|
+
schema: cacheGetSchema
|
|
2070
|
+
}, async (request, reply) => {
|
|
2071
|
+
const ifModifiedSince = request.headers["if-modified-since"];
|
|
2072
|
+
const ifNoneMatch = request.headers["if-none-match"];
|
|
2073
|
+
if (ifModifiedSince ?? ifNoneMatch) {
|
|
2074
|
+
await reply.status(304).send();
|
|
2075
|
+
return;
|
|
2076
|
+
}
|
|
2077
|
+
await reply.send("Cache content or resource response here.");
|
|
2078
|
+
});
|
|
2079
|
+
fastify.get("/cache/:value", {
|
|
2080
|
+
schema: cacheSetSchema
|
|
2081
|
+
}, async (request, reply) => {
|
|
2082
|
+
const { value } = request.params;
|
|
2083
|
+
await reply.header("Cache-Control", `max-age=${value}`).send(`Cache-Control set for ${value} seconds.`);
|
|
2084
|
+
});
|
|
2085
|
+
}, "cacheRoutes");
|
|
2086
|
+
|
|
2087
|
+
// src/routes/response-inspection/etag.ts
|
|
2088
|
+
var etagSchema = {
|
|
2089
|
+
description: "Handles ETag-based conditional requests.",
|
|
2090
|
+
tags: [
|
|
2091
|
+
"Response Inspection"
|
|
2092
|
+
],
|
|
2093
|
+
params: {
|
|
2094
|
+
type: "object",
|
|
2095
|
+
properties: {
|
|
2096
|
+
etag: {
|
|
2097
|
+
type: "string",
|
|
2098
|
+
description: "The ETag value for the resource."
|
|
2099
|
+
}
|
|
1555
2100
|
},
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
fastify.get(
|
|
1565
|
-
"/text",
|
|
1566
|
-
{
|
|
1567
|
-
schema: textSchema
|
|
2101
|
+
required: [
|
|
2102
|
+
"etag"
|
|
2103
|
+
]
|
|
2104
|
+
},
|
|
2105
|
+
response: {
|
|
2106
|
+
200: {
|
|
2107
|
+
type: "string",
|
|
2108
|
+
description: "Resource content for matching ETag."
|
|
1568
2109
|
},
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
const text = randomTexts[randomIndex];
|
|
1573
|
-
reply.type("text/plain");
|
|
1574
|
-
return text;
|
|
1575
|
-
}
|
|
1576
|
-
);
|
|
1577
|
-
fastify.get(
|
|
1578
|
-
"/html",
|
|
1579
|
-
{
|
|
1580
|
-
schema: htmlSchema
|
|
2110
|
+
304: {
|
|
2111
|
+
type: "null",
|
|
2112
|
+
description: "Indicates the resource has not been modified."
|
|
1581
2113
|
},
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
2114
|
+
412: {
|
|
2115
|
+
type: "null",
|
|
2116
|
+
description: "Indicates a precondition failed due to mismatched ETag."
|
|
2117
|
+
}
|
|
2118
|
+
}
|
|
2119
|
+
};
|
|
2120
|
+
var etagRoutes = /* @__PURE__ */ __name((fastify) => {
|
|
2121
|
+
fastify.get("/etag/:etag", {
|
|
2122
|
+
schema: etagSchema
|
|
2123
|
+
}, async (request, reply) => {
|
|
2124
|
+
const { etag } = request.params;
|
|
2125
|
+
const ifNoneMatch = request.headers["if-none-match"];
|
|
2126
|
+
const ifMatch = request.headers["if-match"];
|
|
2127
|
+
if (ifNoneMatch === etag) {
|
|
2128
|
+
await reply.status(304).send();
|
|
2129
|
+
return;
|
|
2130
|
+
}
|
|
2131
|
+
if (ifMatch && ifMatch !== etag) {
|
|
2132
|
+
await reply.status(412).send();
|
|
2133
|
+
return;
|
|
2134
|
+
}
|
|
2135
|
+
await reply.header("ETag", etag).send("Resource content for matching ETag.");
|
|
2136
|
+
});
|
|
2137
|
+
}, "etagRoutes");
|
|
1591
2138
|
|
|
1592
2139
|
// src/routes/response-inspection/response-headers.ts
|
|
1593
2140
|
import { escape as escapeHtml } from "html-escaper";
|
|
@@ -1988,7 +2535,7 @@ import { fastifySwaggerUi } from "@fastify/swagger-ui";
|
|
|
1988
2535
|
// package.json
|
|
1989
2536
|
var package_default = {
|
|
1990
2537
|
name: "@jaredwray/mockhttp",
|
|
1991
|
-
version: "0.
|
|
2538
|
+
version: "0.9.0",
|
|
1992
2539
|
description: "Mock Http - Easy way to mock http with httpbin replacement",
|
|
1993
2540
|
type: "module",
|
|
1994
2541
|
main: "dist/index.js",
|
|
@@ -2130,6 +2677,7 @@ var MockHttp = class extends Hookified {
|
|
|
2130
2677
|
redirects: true,
|
|
2131
2678
|
requestInspection: true,
|
|
2132
2679
|
responseInspection: true,
|
|
2680
|
+
responseFormats: true,
|
|
2133
2681
|
statusCodes: true,
|
|
2134
2682
|
cookies: true,
|
|
2135
2683
|
anything: true,
|
|
@@ -2272,7 +2820,7 @@ var MockHttp = class extends Hookified {
|
|
|
2272
2820
|
if (this._apiDocs) {
|
|
2273
2821
|
await this.registerApiDocs();
|
|
2274
2822
|
}
|
|
2275
|
-
const { httpMethods, redirects, requestInspection, responseInspection, statusCodes: statusCodes2, cookies, anything, auth } = this._httpBin;
|
|
2823
|
+
const { httpMethods, redirects, requestInspection, responseInspection, responseFormats, statusCodes: statusCodes2, cookies, anything, auth } = this._httpBin;
|
|
2276
2824
|
if (httpMethods) {
|
|
2277
2825
|
await this.registerHttpMethods();
|
|
2278
2826
|
}
|
|
@@ -2285,6 +2833,9 @@ var MockHttp = class extends Hookified {
|
|
|
2285
2833
|
if (responseInspection) {
|
|
2286
2834
|
await this.registerResponseInspectionRoutes();
|
|
2287
2835
|
}
|
|
2836
|
+
if (responseFormats) {
|
|
2837
|
+
await this.registerResponseFormatRoutes();
|
|
2838
|
+
}
|
|
2288
2839
|
if (redirects) {
|
|
2289
2840
|
await this.registerRedirectRoutes();
|
|
2290
2841
|
}
|
|
@@ -2374,9 +2925,12 @@ var MockHttp = class extends Hookified {
|
|
|
2374
2925
|
const fastify = fastifyInstance ?? this._server;
|
|
2375
2926
|
await fastify.register(cacheRoutes);
|
|
2376
2927
|
await fastify.register(etagRoutes);
|
|
2377
|
-
await fastify.register(plainRoute);
|
|
2378
2928
|
await fastify.register(responseHeadersRoutes);
|
|
2379
2929
|
}
|
|
2930
|
+
async registerResponseFormatRoutes(fastifyInstance) {
|
|
2931
|
+
const fastify = fastifyInstance ?? this._server;
|
|
2932
|
+
await fastify.register(responseFormatRoutes);
|
|
2933
|
+
}
|
|
2380
2934
|
/**
|
|
2381
2935
|
* Register the redirect routes.
|
|
2382
2936
|
* @param fastifyInstance - the server instance to register the routes on.
|