| 153 | } |
| 154 | |
| 155 | std::string sanitizeFileName(const std::string& name) |
| 156 | { |
| 157 | // A payload name never legitimately carries a directory: a backup with |
| 158 | // subfolders travels as a zip. Keep the basename and drop the rest. |
| 159 | size_t slash = name.find_last_of("/\\"); |
| 160 | std::string base = (slash == std::string::npos) ? name : name.substr(slash + 1); |
| 161 | |
| 162 | std::string out; |
| 163 | out.reserve(base.size()); |
| 164 | for (unsigned char c : base) { |
| 165 | // Control characters and the characters FAT rejects go; '.' and the |
| 166 | // bytes of a multi-byte UTF-8 sequence stay. |
| 167 | if (c < 0x20 || c == ':' || c == '*' || c == '?' || c == '"' || c == '<' || c == '>' || c == '|') { |
| 168 | continue; |
| 169 | } |
| 170 | out.push_back((char)c); |
| 171 | } |
| 172 | |
| 173 | // "." and ".." name directories, not files that can be created. |
| 174 | if (out == "." || out == "..") { |
| 175 | return ""; |
| 176 | } |
| 177 | return out; |
| 178 | } |
| 179 | |
| 180 | // Field names are case-insensitive (RFC 9110 5.1). Go's net/http canonicalises |
| 181 | // them before writing, so chlink's "X-CP-Token" reaches us as "X-Cp-Token": a |
no test coverage detected