{"record":{"id":"26b8a0ec1d399618","repo":"DIYgod/RSSHub","slug":"invalid-pub","errorCode":null,"errorMessage":"Invalid pub","messagePattern":"Invalid pub","errorType":"validation","errorClass":"InvalidParameterError","httpStatus":503,"severity":"error","filePath":"lib/routes/aip/journal-pupp.ts","lineNumber":17,"sourceCode":"import { load } from 'cheerio';\n\nimport { config } from '@/config';\nimport InvalidParameterError from '@/errors/types/invalid-parameter';\nimport cache from '@/utils/cache';\nimport playwright from '@/utils/playwright';\nimport { isValidHost } from '@/utils/valid-host';\n\nimport { playwrightGet, renderDesc } from './utils';\n\nconst handler = async (ctx) => {\n    const pub = ctx.req.param('pub');\n    const jrn = ctx.req.param('jrn');\n    const host = 'https://pubs.aip.org';\n    const jrnlUrl = `${host}/${pub}/${jrn}/issue`;\n    if (!isValidHost(pub)) {\n        throw new InvalidParameterError('Invalid pub');\n    }\n\n    // use Playwright due to the obstacle by cloudflare challenge\n    const context = await playwright();\n\n    const { jrnlName, list } = await cache.tryGet(\n        jrnlUrl,\n        async () => {\n            const response = await playwrightGet(jrnlUrl, context);\n            const $ = load(response);\n            const jrnlName = $('.header-journal-title').text();\n            const list = $('.card')\n                .toArray()\n                .map((item) => {\n                    $(item).find('.access-text').remove();\n                    const title = $(item).find('.hlFld-Title').text();\n                    const authors = $(item).find('.entryAuthor.all').text();\n                    const img = $(item).find('img').attr('src');","sourceCodeStart":1,"sourceCodeEnd":35,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/aip/journal-pupp.ts#L1-L35","documentation":"The AIP (American Institute of Physics) route builds the URL `https://pubs.aip.org/${pub}/${jrn}/issue`. isValidHost rejects `pub` values that are not a clean single DNS label, preventing path/host injection (dots, slashes, etc.) into the URL.","triggerScenarios":"Calling /aip/journal-pupp/:pub/:jrn where `pub` contains dots, slashes, or other characters that make it not a valid single-label hostname — e.g. passing the full URL or a multi-segment path.","commonSituations":"Passing 'pubs.aip.org' as pub; including a leading slash; using a journal code where the publisher code should go.","solutions":["Pass only the publisher/path segment as it appears in the route example — a single label with no dots or slashes.","Check the route's `example` field for the canonical pub/jrn pair.","Confirm `jrn` is also a single path segment."],"exampleFix":"// before\n/aip/journal-pupp/pubs.aip.org/physicstoday\n// after\n/aip/journal-pupp/<publisher-label>/physicstoday   // single-label pub","handlingStrategy":"validation","validationCode":"import { isValidHost } from '@/utils/valid-host';\nfunction validAipPub(pub) {\n  return isValidHost(pub) && /^[a-z0-9-]+$/i.test(pub);\n}","typeGuard":"function isAipPubLabel(p): p is string {\n  return typeof p === 'string' && /^[a-z0-9-]+$/i.test(p) && !p.includes('.') && !p.includes('/');\n}","tryCatchPattern":null,"preventionTips":["Pass only the single-label publisher segment, never the full hostname.","Mirror the route's `example` for the canonical pub/jrn pair.","Reject any pub containing '.', '/', or '@' before building the URL."],"tags":["validation","host-injection","parameter","rsshub","ssrf"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}