You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

74 lines
1.7 KiB

  1. "use strict";
  2. const MIMEType = require("whatwg-mimetype");
  3. const { parseURL, serializeURL } = require("whatwg-url");
  4. const {
  5. stripLeadingAndTrailingASCIIWhitespace,
  6. stringPercentDecode,
  7. isomorphicDecode,
  8. forgivingBase64Decode
  9. } = require("./utils.js");
  10. module.exports = stringInput => {
  11. const urlRecord = parseURL(stringInput);
  12. if (urlRecord === null) {
  13. return null;
  14. }
  15. return module.exports.fromURLRecord(urlRecord);
  16. };
  17. module.exports.fromURLRecord = urlRecord => {
  18. if (urlRecord.scheme !== "data") {
  19. return null;
  20. }
  21. const input = serializeURL(urlRecord, true).substring("data:".length);
  22. let position = 0;
  23. let mimeType = "";
  24. while (position < input.length && input[position] !== ",") {
  25. mimeType += input[position];
  26. ++position;
  27. }
  28. mimeType = stripLeadingAndTrailingASCIIWhitespace(mimeType);
  29. if (position === input.length) {
  30. return null;
  31. }
  32. ++position;
  33. const encodedBody = input.substring(position);
  34. let body = stringPercentDecode(encodedBody);
  35. // Can't use /i regexp flag because it isn't restricted to ASCII.
  36. const mimeTypeBase64MatchResult = /(.*); *[Bb][Aa][Ss][Ee]64$/.exec(mimeType);
  37. if (mimeTypeBase64MatchResult) {
  38. const stringBody = isomorphicDecode(body);
  39. body = forgivingBase64Decode(stringBody);
  40. if (body === null) {
  41. return null;
  42. }
  43. mimeType = mimeTypeBase64MatchResult[1];
  44. }
  45. if (mimeType.startsWith(";")) {
  46. mimeType = "text/plain" + mimeType;
  47. }
  48. let mimeTypeRecord;
  49. try {
  50. mimeTypeRecord = new MIMEType(mimeType);
  51. } catch (e) {
  52. mimeTypeRecord = new MIMEType("text/plain;charset=US-ASCII");
  53. }
  54. return {
  55. mimeType: mimeTypeRecord,
  56. body
  57. };
  58. };