- All Implemented Interfaces:
Serializable, Servlet, ServletConfig
- See Also:
Nested Class Summary
Nested ClassesModifier and TypeClassDescription(package private) static classResult of building the new announce list.(package private) static classParsed announce parameters from the create torrent form.private static classCached per-torrent values used by the status-cell destination badge: the four-character base64 destination prefix and the client identity display name, if any.(package private) static classResult of validating a base file for torrent creation.(package private) static classImmutable parameters for rendering the comments/ratings section.(package private) static classSnapshot read atomically from a torrent's comment set: the user's own rating, community rating count and average, and an iterator over the existing comments when any exist.(package private) static classResult of building the announce list.(package private) static classParsed edit form parameters.(package private) static classImmutable context for rendering a single file row in the torrent file browser.(package private) static classMutable counters for file row rendering.(package private) static classAggregated footer state, replacing a twelve-parameter signature.private static classHolds immutable mappings from MIME types and file suffixes to icon names.private static classSort by completeness (seeds first), then by ID.(package private) static classImmutable context for rendering a peer row.(package private) static classPeer status classification result.private static classPer-row and per-render inputs fordisplaySnark(PrintWriter, I2PSnarkServlet.RowContext, StringBuilder), replacing an eighteen-parameter signature.(package private) static classRequest-derived inputs shared by every sortable torrent-list header cell; replaces a thirteen-parameter signature.(package private) static enumThe mutually exclusive states a torrent row can display, in the evaluation order ofclassifyStatus(boolean, boolean, boolean, boolean, boolean, boolean, int, int, boolean, boolean).private static classEncapsulates result of status building with HTML output and status keyword.(package private) static classPeer/rate activity flags scanned across one rendered page slice; drives which optional header cells render.Nested classes/interfaces inherited from class BasicServlet
BasicServlet.HttpContentModifier and TypeClassDescriptionstatic interfaceFrom Jetty HttpContent.java.Field Summary
Modifier and TypeFieldDescriptionprivate static booleanSet once when an outdated I2PSnark Bridge extension reported itself; one screen-log notice per webapp start.private static StringVersion of the bundled I2PSnark Bridge XPI, read lazily from the war; null if unknown.private StringContext display name, generally "i2psnark"; set once in init().private StringContext path, generally "/i2psnark"; set once inGenericServlet.init().private longRotating CSRF nonce, rotates every 5 minutes.private static final ThreadLocal<DateFormat> Per-thread date format for the torrent list.private static final ThreadLocal<DateFormat> Per-thread date format including the time.private static final ThreadLocal<DateFormat> Per-thread date format for file timestamps.private StringIcon image base path derived from_themePath.private StringAnnounce URL of the torrent being edited; preselects its tracker radio button.private longWhen the current nonce was minted, ms since epoch; drives rotation.private SnarkManagerThe manager holding this webapp's torrents.private final long[]The two nonces before the current one, still accepted for in-flight forms.private StringWeb path of static resources; set once in init(), never mutated per request.private StringWeb path of the active theme's resources; recomputed per request.private static final StringBase32 address of the Actix tracker.private static final PatternMatches a base32 name without the suffix.private static final StringKnown tracker base32 announces.private static final StringBase32 address of the Chudo tracker.private final I2PSnarkConfigureSettings form writer, which reads its settings back through this servlet's accessors.private static final StringBase32 address of the Cryptopolis tracker.(package private) StringCsp nonce.private static final StringWebapp name used in paths and config keys.private static final String[]Command keys accepted byexecuteDirectoryPostAction(Snark, Map, String), in precedence order.private static final StringDocument type line opening every page.private static final StringBase32 address of the FattyDove tracker.private static final StringThe html footer of the page.private static final StringThe html footer of the standalone page.private static final StringBase32 address of the Freedom tracker.(package private) static final charEllipsis character used to truncate long names.private static final PatternMatches a hex info hash.private static final StringBase32 address of the ICU812 tracker.private static final StringHidden iframe that receives form posts.private static final PatternSplits a pasted info hash from a trailing parenthetical.(package private) static final String[][]Known tracker announce keys (base64 postman blobs and base32 hostnames) mapped to their display names.private static final StringBase32 address of the LocalCache tracker.private static final StringBase32 address of the Lodikon tracker.private static final StringBase32 address of the Lyoko tracker.(package private) static final intLongest file name shown before truncation.private static final longForm nonces rotate every 5 minutes.private static final StringBase32 address of the Observations tracker.private static final StringBase32 address of the Odift tracker.private static final StringBase32 address of the Omirack tracker.private static final StringBase32 address of the OnionTracker tracker.private static final StringBase32 address of the Postman tracker's new address.private static final StringKnown postman tracker base64 announce, both old and new.private static final StringBase64 destination of the Postman tracker's new address.private static final StringConfig key for the console's advanced mode.static final StringConfig file path property.private static final StringBase32 address of the Public tracker.private static final StringBase32 address of the R4SAS tracker.private static final StringConfig key for the console's Sora font option.private intSearch results.private static final longFixed serial version for the servlet.private static final StringBase32 address of the Sigma tracker.private static final StringBase32 address of the SIMP tracker.private static final StringBase32 address of the Skank tracker.private static final intSort key for the download rate column.private static final intCumulative stats array indices: [downloaded, uploaded, download rate, upload rate, peers, total size].private static final intSort key for the peers column.private static final intSort key for the total size column.private static final intSort key for the upload rate column.private static final intSort key for the uploaded column.private static final intRows rendered per chunk in streamed mode; bounds the staging buffer near tens of KB.private static final intMinimum visible rows before a directory file table renders in streamed mode.private static final intMinimum visible rows before a torrent-list page renders in streamed mode.private static final StringOpening of the torrent list table.private static final StringBase32 address of The Bland tracker.static final StringWebapp resource base path.private static final StringBase32 address of the YetAnother tracker.Fields inherited from class BasicServlet
_context, _log, _resourceBaseModifier and TypeFieldDescriptionprotected final I2PAppContextThe global application context, transient so the servlet stays serializable.protected final LogLog for this servlet's class, transient so the servlet stays serializable.protected FileBase directory for serving static files.Constructor Summary
ConstructorsConstructorDescriptionConstructor called by the servlet container; all setup is deferred to init().Method Summary
Modifier and TypeMethodDescription(package private) StringTranslate a string.(package private) StringTranslate a string with one argument.(package private) StringTranslate a string with two arguments.private voidAdd a torrent from a magnet URL.private booleanallowOrigin(HttpServletRequest request) Validate Origin header for POST requests.private voidappendActionsHeader(StringBuilder buf, List<Snark> snarks, boolean isConnected, boolean noSnarks, String txtStartAll, String txtStopAll, String txtStopAllTitle, String txtStartAllTitle, String txtStartStoppedTitle) Action column: Stop All always when connected; Start All variants depending on whether any listed torrent is stopped.private voidappendDebugRow(PrintWriter out, DHT dht, String peerParam) Renders the DHT debug row as the second row of the snark footer, hidden unless debug mode (?p=2) is active.private voidappendEtaHeader(StringBuilder buf, I2PSnarkServlet.SortHeaderContext hc, String txtETA, boolean isConnected, boolean noSnarks, I2PSnarkServlet.TorrentActivityScan scan) ETA column: sortable only while something on the page is downloading.private voidappendFileTableHead(StringBuilder buf, String base, String directory, int dirSlash, boolean isTopLevel, boolean showSort, boolean showPriority, String sortParam) Renders the sortable column headers of the files table: Directory/ Name-type, Size, Download Status (only when priorities are shown) and Download Priority (same condition).private static voidappendHiddenInput(StringBuilder buf, String name, String value, boolean esc) Append a single hidden form input.(package private) voidappendIcon(StringBuilder buf, String name, String alt, String title, boolean fromTheme, boolean isSvg) Overloaded method that defaults addDimensions to false.(package private) voidappendIcon(StringBuilder buf, String name, String alt, String title, boolean fromTheme, boolean isSvg, boolean addDimensions) Appends a<img>tag for an icon to the given StringBuilder.private static voidappendMediaSection(StringBuilder buf, String base, String tName, String mime, boolean isAudio, String imgPath) Renders the HTML5 audio/video player section for a complete single-media torrent.private voidappendNameTypeHeader(StringBuilder buf, I2PSnarkServlet.SortHeaderContext hc, String txtTorrent) Torrent name/type column: cycles vianextTorrentNameTypeSort(String); active-state detection mirrors the five name/type keys.private voidappendNavbar(StringBuilder buf, boolean isConfigure, String peerString, List<Tracker> sortedTrackers) Renders the navbar: configure variant links back to the torrent list; list variant adds tracker links from the sorted tracker list.private voidappendParentDirRow(StringBuilder buf, String base, String sortParam, String decodedBase, boolean isTopLevel, boolean hasAudio, boolean showPriority) Renders the dirNav row below the column headers: the parent-directory link (subdirectories only) and the audio-playlist button when complete audio exists at or below this point.private voidappendPeerRow(StringBuilder buf, Peer peer, Snark snark, MetaInfo meta, boolean noThinsp) Appends HTML for a single peer row to the given StringBuilder.private voidappendPeerToggleHeader(StringBuilder buf, I2PSnarkServlet.SortHeaderContext hc, String peerParam, boolean isConnected, boolean noSnarks, I2PSnarkServlet.TorrentActivityScan scan) Peer-count column: renders the show/hide peers toggle when connected with peers present; empty cell otherwise.private voidappendPriority(StringBuilder buf, boolean showPriority, boolean complete, boolean isDirectory, int priority, int fileIndex) Appends the HTML markup for the file download priority options in torrent file listings.private static voidappendQueryParam(StringBuilder buf, HttpServletRequest req, String name, String override) Append one query pair to buf if it resolves to an emittable value.private voidappendRateDownHeader(StringBuilder buf, I2PSnarkServlet.SortHeaderContext hc, String txtRXRate, String txtRX, String peerParam, boolean isConnected, boolean noSnarks, I2PSnarkServlet.TorrentActivityScan scan) Download-rate column: sortable only while downloading; direction icon reflects the current key.private voidappendRateUpHeader(StringBuilder buf, I2PSnarkServlet.SortHeaderContext hc, String txtTXRate, boolean isConnected, boolean noSnarks, I2PSnarkServlet.TorrentActivityScan scan) Upload-rate column: sortable only while uploading; ascending icon when currently on "9" (note the inverted default versus rateDown).private voidappendResourceError(StringBuilder buf, File r, String base, String tName) Renders the error table shown when the requested path within the torrent does not exist on disk.private voidappendRxHeader(StringBuilder buf, I2PSnarkServlet.SortHeaderContext hc, String txtRX, boolean noSnarks) RX column: four-state cycle vianextRXSort(String)whenever the list is sortable; empty cell otherwise.private voidappendSearchForm(StringBuilder buf, HttpServletRequest req) Renders the search form when multiple torrents exist; hidden until realtimeSearch.js activates it, functional without JS via GET submit.private voidAppends the footer section for the torrent list table, displaying overall statistics, counters, and status indicators with associated icons.private StringappendSnarkHeader(HttpServletRequest req, List<Snark> snarks, int start, int pageSize, String filterParam, String peerParam, String currentSort, String contextPath) Builds the HTML table header row for the torrent list display, including sortable column headers, peer toggling links, and activity indicators.private voidappendSortHeader(StringBuilder buf, I2PSnarkServlet.SortHeaderContext hc, String newSort, String cssClass, String iconName, String title, boolean showSort, boolean currentSortMatches, boolean isDescending) Appends a sortable table header cell including sort icons and links.private voidappendSortToggleLink(StringBuilder buf, String base, String icon, String label, String tooltip, String nextSort, String id) Appends an icon-only column-header link that toggles to nextSort on click.private voidappendStatusHeader(StringBuilder buf, I2PSnarkServlet.SortHeaderContext hc, boolean poolSort, String txtStatus) Status column: sortable always; pool-aware vianextStatusSort(String, boolean).private voidappendTorrentActionButton(StringBuilder buf, String action, String token, Snark snark, String title) Append a Remove or Delete submit button for a torrent row.private voidappendTorrentInfo(StringBuilder buf, Snark snark, String base, String tName, boolean showStopStart) Appends detailed torrent information as HTML to the provided StringBuilder buffer.private voidappendTxHeader(StringBuilder buf, I2PSnarkServlet.SortHeaderContext hc, String txtTX) TX column: four-state cycle vianextTXSort(String)whenever the list is sortable; empty cell otherwise.private I2PSnarkServlet.BadgeInfobadgeInfo(I2PSnarkServlet.RowContext rc, Snark snark) Look up (or compute) the badge values for a torrent.static booleanbrowserApiAuthorized(boolean enabled, boolean hostAllowed, String providedKey, String configuredKey) Pure decision function for browser API authorization (unit-testable): requires the API to be enabled and the client to be an allowed host or to present the configured API key.private booleanWhether the browser API request is authorized.private StringThe console base URL for this request, e.g.private StringbrowserApiName(String url) Validate the browser API payload and extract a display name for the OK reply.(package private) static I2PSnarkServlet.AnnounceListResultbuildAnnounceList(MetaInfo meta, I2PSnarkServlet.EditParams ep, List<Tracker> trackers, boolean udpEnabled) Builds the new announce list and primary tracker from the current MetaInfo and edit parameters.(package private) static I2PSnarkServlet.CreateAnnounceListResultbuildAnnounceList(I2PSnarkServlet.AnnounceParams params, List<String> privateTrackers) Builds the tiered announce list from primary and backup URLs.static StringbuildBridgeMetaTag(String baseUrl) The meta element advertising the base URL of the I2PSnark webapp that served this page, so the I2PSnark Bridge extension's content script can discover the exact origin + context path (host, port, https) and route subsequent magnet: handoffs to it.private StringbuildFilterLink(String baseUrl, String filterId, boolean visible, String title, String badgeText) Builds an HTML filter link anchor element with an optional badge and visibility toggle.(package private) static StringComposes a link URL from a path, a servlet-generated query string, and extra query text, choosing the '?'/'&' separators by inspection rather than by caller-supplied guesses about the raw request.private StringbuildProgressBar(long total, long remaining, boolean includePercent, boolean includeTooltip, boolean noThinsp, boolean formatSize) Builds an HTML progress bar with optional percentage text and a tooltip showing the remaining size and completion percentage.private StringbuildSimpleFilterLink(String baseUrl, String filterId, String title, String badge) Builds a simple HTML filter link anchor element with a badge but no visibility toggle.private I2PSnarkServlet.StatusResultbuildStatusString(Snark snark, int curPeers, int knownPeers, long downBps, long upBps, boolean isRunning, long remaining, long needed, boolean noThinsp) Generates HTML status string and status code for a Snark based on its state and peer info.private booleancheckNestedTorrent(File dataDir, boolean checkContained) Reject a torrent whose data directory lies inside another torrent's data directory, or (when checkContained) would contain another torrent's data directory.(package private) static I2PSnarkServlet.PeerStatusclassifyPeerStatus(Peer peer) Determines the peer status (active/inactive with TX/RX flags).(package private) static I2PSnarkServlet.StatusKindclassifyStatus(boolean allocating, boolean checking, boolean starting, boolean trackerProblems, boolean running, boolean complete, int curPeers, int knownPeers, boolean uploading, boolean downloading) Pure decision function mirroring the historical if/else cascade ofbuildStatusString(Snark, int, int, long, long, boolean, long, long, boolean), extracted so state classification can be tested without rendering.(package private) I2PSnarkConfigureThe settings form writer.(package private) I2PAppContextcontext()The I2P context this servlet runs in.(package private) StringThe name identifying this instance in config and titles.(package private) StringThe context path this servlet is mounted under.private static StringGenerates a CSS link tag for the given filename.private voiddeleteComments(Snark snark, Map<String, String[]> postParams) Delete comments for a torrent.voiddestroy()Destroy the servlet.private voiddisplayComments(Snark snark, boolean er, boolean ec, boolean esc, StringBuilder buf) Display the ratings and comments section.private voiddisplaySnark(PrintWriter out, I2PSnarkServlet.RowContext rc, StringBuilder buf) Displays a single snark (torrent) as an HTML table row, including optional peer rows.private voiddisplayTorrentEdit(Snark snark, String base, StringBuilder buf) Display the edit-torrent section.voiddoGet(HttpServletRequest request, HttpServletResponse response) Handle what we can here, calling super.doGet(HttpServletRequest, HttpServletResponse)for the rest.private voiddoGetAndPost(HttpServletRequest req, HttpServletResponse resp) Handle what we can here, calling super.doGet() or super.doPost() for the rest.voiddoPost(HttpServletRequest request, HttpServletResponse response) Handle what we can here, calling super.doPost(HttpServletRequest, HttpServletResponse)for the rest.(package private) static booleandrainTo(PrintWriter out, StringBuilder buf) Pushes staged markup to the response writer and empties the buffer, forcing bytes toward the client so large pages render progressively.private voidemitGraphData(HttpServletRequest req, PrintWriter out) Emits the bandwidth graph element for xhr1 payloads.(package private) static StringEscape a string for embedding in an HTML attribute value that page scripts read back into JavaScript strings, e.g.private voidPerforms the side effects of a validated directory-page POST command.private StringExtracts the action parameter from the request.private String[]extractTorrentNameAndPath(String title) Extracts the torrent name and path-in-torrent from the given title.(package private) static StringfindCompleteFile(List<String> names, long[] remaining, String prefix, java.util.function.Predicate<String> match) First entry of names at or under prefix whose remaining byte count is zero and whose name satisfies match, or null.(package private) static StringfindPostAction(Map<String, String[]> postParams) Returns the first matching command key from a directory-page POST, in the fixed precedence order ofDIRECTORY_POST_ACTIONS.private static StringformatSize(long bytes) Format the file size.private StringformatSizeSpans(String formattedSize, boolean closeLeftSpan) Formats a human-readable size string by wrapping unit characters (B, K, M, G, T) in HTML span tags with CSS classes for styling.(package private) StringThe version of the I2PSnark Bridge extension bundled in this war, read once from the XPI's manifest.json; null if it cannot be determined.private StringgetClientName(Peer peer) Returns a human-readable name of the client associated with the given Peer.(package private) StringgetListHTML(File xxxr, String base, boolean parent, Map<String, String[]> postParams, String sortParam, PrintWriter out) Modded heavily from the Jetty version in Resource.java, pass Resource as 1st param All the xxxResource constructors are package local so we can't extend them.private longgetNonce()Current CSRF nonce, rotating every 5 minutes.private voidgetPlaylist(StringBuilder buf, List<Sorters.FileAndIndex> fileList, String reqURL, int sort, Storage storage, long[] remainingArray) Append playlist entries in m3u format to buf.private StringgetPlaylist(String reqURL, String base, String sortParam) The audio files in the resource list as an m3u playlist.private static StringgetQueryString(HttpServletRequest req, String p, String st, String so, String search) Query string with an optional search override.getResource(String pathInContext) We override this to set the file relative to the storage directory for the torrent.private StringgetShortTrackerLink(String announce, byte[] infohash) Full anchor to the home page or details page with shortened hostname as anchor text.Returns the list of torrents sorted according to the current request's sort parameter.private StringgetTrackerLink(String announce, byte[] infohash) Full link to the details page with an image.private StringgetTrackerLinkUrl(String announce, byte[] infohash) Link to the details page if the tracker supports it.private voidHandles the "Add" action, processes file uploads or URLs to add torrents.private voidhandleAddFile(String newFile, File torrentDir, File dataDir, RequestWrapper reqw) Handles adding a torrent from an uploaded file.private voidhandleAddFromFilePath(String newURL, File dataDir) Handles adding a torrent from a file path.private voidhandleAddURL(String newURL, File dataDir, RequestWrapper reqw) Handles adding a torrent from a URL or magnet link.private booleanhandleAjaxRequest(String path, boolean isConfigure, String peerString, HttpServletRequest req, HttpServletResponse resp) Serves the XHR fragment endpoints; unknown paths are ignored so the caller's fall-through routing stays in charge.private voidNonce-free browser API: adds a magnet link, torrent URL, info hash, or local torrent file path.private voidHandles clearing messages by id.private voidHandles creating a new torrent from provided base file or directory.private voidhandleDelete(String action) Handles the "Delete_" action to delete a torrent and its data by action token.private voidhandleDirectoryPost(Snark snark, Map<String, String[]> postParams) Dispatch a POST on the torrent directory page to its action, validating the anti-CSRF nonce first.private booleanhandleFormSubmission(HttpServletRequest req, HttpServletResponse resp, String method, String peerString) Dispatches a nonce-bearing form submission to its action and finishes with the P-R-G redirect (or G-R-G to hide params from the address bar).private voidThe page the browser opens when a magnet: link is handed to the I2PSnark Bridge extension (registered via protocol_handlers in the extension manifest).private voidhandleRemove(String action) Handles the "Remove_" action to remove a torrent by action token.private booleanhandleSave(HttpServletRequest req, HttpServletResponse resp) Handles saving configuration updates.private voidHandles saving torrent creation filter form updates.private voidHandles saving tracker form updates.private voidhandleStart(String action) Handles the "Start_" action to start a torrent by action token.private voidHandles starting all torrents or search-filtered torrents.private voidhandleStop(String action) Handles the "Stop_" action to stop a torrent by action token.private voidHandles stopping all torrents or search-filtered torrents.private voidhandleUnmanagedPath(HttpServletRequest req, HttpServletResponse resp, String method, String path) Answers everything outside the managed pages: torrent directory listings (with optional playlist export) under trailing-slash paths, and container delegation for the rest.(package private) static booleanhasChanges(MetaInfo meta, I2PSnarkServlet.EditParams ep) Determines whether the edit parameters represent any actual change to the torrent's metadata.private booleanhasCompleteAudio(Storage storage, long[] remainingArray, String prefix) Whether any complete audio file exists at or below the browsed directory.voidinit(ServletConfig cfg) Initialize the servlet.private StringinjectPoolBadge(String statusHtml, Snark snark, I2PSnarkServlet.RowContext rc) Injects the multi-dest pool badge into the status cell HTML.private booleanInstalls the I2PSnark Bridge extension that forwards magnet links to the browser API endpoint.booleanReturns whether advanced mode is enabled in the router console.(package private) static booleanisAjaxPath(String path) The two XHR fragment endpoints polled by the console JS.private static booleanWhether the MIME type is audio.static booleanWhether the given User-Agent header indicates a Firefox-family browser (Firefox, LibreWolf, Waterfox, Pale Moon, Tor Browser), which can install the I2PSnark Bridge extension.(package private) static booleanisI2PTracker(String url, boolean udpEnabled) Basic checks only, not as comprehensive as what TrackerClient does.(package private) static booleanisIndexPath(String path) Whether path is the torrent list landing page.(package private) static booleanisPaddingDir(File f) Whether a filesystem entry is a legacy padding directory that should be hidden in top-level listings.private static booleanisParentOf(File a, File b) Whether "a" equals "b", or "a" is a directory and a parent of file or directory "b", canonically speaking.(package private) booleanWhether we are running in standalone mode.(package private) static booleanisTypeSortNext(String sortParam) Whether the Directory column's next sort target is the file type, i.e.(package private) static booleanisUnmanagedPath(String path, boolean isIndex, boolean isConfigure) Paths that bypass normal page rendering and are answered by handleUnmanagedPath: everything outside the index page(s), the POST target, and the configuration UI.static booleanValidates if a string is a valid 32-base32 character info hash.static booleanValidates if a string is a valid 40-hex character info hash.private booleanisValidNonce(String nonce) Validate nonce against current and recent nonces (backward compatibility).static booleanValidates if string is version 2 hex multihash (68 characters starting with "1220").private static booleanWhether the MIME type is video.static booleanWhether the given User-Agent header indicates Windows, which gets the PowerShell installer script instead of the shell one.private static List<Sorters.FileAndIndex> listFileAndIndex(File dir, Storage storage, long[] remainingArray) List the files in a directory and wrap each in a FileAndIndex with the given remaining array.(package private) SnarkManagermanager()The torrent manager behind this servlet.(package private) booleanWhether multi-destination mode is active: enabled in the config with at least one active destination.(package private) static StringnextNameTypeSort(String sortParam) Next value of the name/file-type sort cycle used by the Directory column header: unset/0/1 sorts name descending ("-1"), which offers the type sort ("12"), whose reverse ("-12") restarts unsorted ("").(package private) static StringnextRXSort(String currentSort) Next value of the RX column cycle: download total and rate alternate asc/desc across four states; unknown keys restart at "-5".(package private) static StringnextStatusSort(String currentSort, boolean poolSort) Next value of the Status column sort cycle: toggles status asc/desc, and in multi-destination mode continues into status+pool asc/desc before returning to status desc.(package private) static StringnextTorrentNameTypeSort(String currentSort) Name/type ladder for the torrent column.(package private) static StringnextTXSort(String currentSort) Next value of the TX column cycle: upload total and share ratio alternate asc/desc across four states; unknown keys restart at "-7".(package private) StringTranslate a pluralized string.(package private) static booleanWhether the user agent cannot handle collapsible panels.private static StringnormalizeSortParam(String sort) Normalize a human-readable sort parameter to its legacy numeric form, e.g.private voidpaginator(PrintWriter out, HttpServletRequest req, int start, int pageSize, int total, String filter, boolean noThinsp, boolean isForm, boolean searchActive, int searchLength) Renders the page navigation controls with visibility handling.(package private) static I2PSnarkServlet.AnnounceParamsParses announce URL and backup tracker URLs from the request.(package private) static List<TorrentCreateFilter> parseCreateFilters(HttpServletRequest req, Map<String, TorrentCreateFilter> filterMap) Parses the selected torrent creation filters from the request.(package private) static I2PSnarkServlet.EditParamsparseEditParams(Map<String, String[]> postParams) Parses the edit form POST parameters into anI2PSnarkServlet.EditParamsobject.(package private) static StringpeerCountHtml(int curPeers, int knownPeers, boolean noThinsp) The peer-count cell shared by most status branches: current peers on the right, known peers in the swarm on the left.(package private) static StringprettyAnnounce(String announce) Rewrite known tracker b64 and b32 announces to their domain names for display.private StringpriorityIcon(int priority) Priority indicator icon (block/skip, clock/normal, red clock/high).private booleanprocessRequest(HttpServletRequest req, HttpServletResponse resp) Process HTTP request to handle torrent-related actions.private voidprocessTorrentCreateFilterForm(String action, HttpServletRequest req) Process torrent create filter form submission.private voidprocessTrackerForm(String action, HttpServletRequest req) Process tracker form submission.private static I2PSnarkServlet.CommentsHeaderResultreadCommentState(CommentSet comments, boolean er, boolean ec) Reads the user's rating, community rating statistics, and the comment iterator from a torrent's comment set within a single lock scope, so markup rendering happens outside synchronized blocks.private voidRenders the commentInfo table header: section title plus the author-name span (the configured name, or a "configure" hint when comments are on for the torrent but no author name is set).private voidrenderCommentsSection(Snark snark, boolean er, boolean ec, boolean esc, String tabLabel, StringBuilder buf) Renders the collapsible comments/ratings section (opener div, toggle, tab label, body, close) when ratings or comments are enabled globally; renders nothing otherwise.private voidrenderDownloadRate(StringBuilder buf, Peer peer, I2PSnarkServlet.PeerRowContext ctx, long needed) Renders the download rate cell.private booleanrenderFileRow(StringBuilder buf, I2PSnarkServlet.FileRowContext ctx, Sorters.FileAndIndex fai, boolean rowEven, I2PSnarkServlet.FileRowCounters counters) Renders a single file row for the torrent file browser table.private voidrenderFilterBar(PrintWriter out, HttpServletRequest req) Renders the torrent filter bar with links for filtering and searching torrents.private StringrenderHead(HttpServletRequest req, boolean isConfigure, boolean isIndex, boolean noCollapse, boolean collapsePanels, boolean showStatusFilter, String peerString, String lang, int delay, int pageSize) Renders the full <head> section of the main HTML page.private voidrenderHeader(StringBuilder buf, String directory) Renders the doctype, HTML head (theme and font CSS, CSP'd theme script, favicon) and the navbar.private voidrenderPeerIdentity(StringBuilder buf, Peer peer, I2PSnarkServlet.PeerRowContext ctx) Renders the peer identity/client section.private voidrenderPeerInactivity(StringBuilder buf, long inactiveTime) Renders the peer inactivity bar if applicable.private floatrenderPeerProgress(StringBuilder buf, Peer peer, I2PSnarkServlet.PeerRowContext ctx) Renders the peer progress bar or seed indicator.private voidrenderUploadRate(StringBuilder buf, Peer peer, I2PSnarkServlet.PeerRowContext ctx, float pct, boolean isValid) Renders the upload rate cell.private SnarkresolveTorrentByToken(String token) Resolves a short action token to its torrent by unique-prefix match over the loaded torrents' base64 info-hash names.private static FileresolveTorrentPath(Storage storage, String pathInTorrent) The on-disk location of a path within a torrent.(package private) StringPrefix for links to resources bundled in the war.private voidsaveComments(Snark snark, Map<String, String[]> postParams) Save comment changes for a torrent.private voidsaveCommentsSetting(Snark snark, Map<String, String[]> postParams) Save comment enabled setting for a torrent.private voidsavePriorities(Snark snark, Map<String, String[]> postParams) Save file priority changes for a torrent.private voidsaveTorrentEdit(Snark snark, Map<String, String[]> postParams) Save edits from the torrent edit form.scanTorrentActivity(List<Snark> snarks, int start, int pageSize, int total) Scans the page slice for peer/rate activity, exiting early once every flag is set.private StringCheap change-detection stamp for the screen log, emitted with every xhr1 refresh payload so the client can skip the xhrscreenlog.html round trip while the log is unchanged.search(String search, Collection<Snark> snarks) Search torrents for matching terms.private voidsendRedirect(HttpServletRequest req, HttpServletResponse resp, String p) Redirect a POST to a GET (P-R-G), preserving the query string.private voidsetHTMLHeaders(HttpServletResponse resp, String cspNonce, boolean allowMedia) Handles the standard HTTP headers for all HTML pages.private voidsetXHRHeaders(HttpServletResponse resp, String cspNonce, boolean allowMedia) Cross-Origin Resource Sharing (CORS) and Content Security Policy (CSP) headers for XMLHttpRequest (XHR) responses.(package private) static booleanshouldStreamFileRows(int visibleRows) Whether a directory file table rendering visibleRows entries uses streamed output.(package private) static booleanshouldStreamTorrentRows(int visibleRows) Whether a torrent list rendering visibleRows entries uses streamed output.private booleansnarkMatchesFilter(Snark s, String filter, String snarkStatus) Checks whether a torrent matches the given filter based on its status string.private static StringSort query string for torrent file-list links, where the value is a servlet-generated numeric sort key.(package private) static StringsuffixIcon(String lowerPath) Icon name registered for a lower-cased path's file extension.private static Stringthinsp(boolean disable) Thin-space markup, disabled if requested.private StringtickIcon()Tick icon for complete files.private StringPick an icon; try to catch the common types in an i2p environment.(package private) StringReturns the icon name representing the file type or mime type of the given file path.private StringtoSVGWithDataTooltip(String icon, String altText, String titleText) Icon file (svg) in the .war.private booleanunlinkTorrentFile(Snark snark) Unlinks a torrent's .torrent file, reporting the outcome as user messages.private static StringThis is for a full URL.(package private) static StringThis is for a full URL.(package private) static StringThis is for a full URL.booleanReturns whether the Sora display font should be used.(package private) static I2PSnarkServlet.BaseFileValidationResultvalidateBaseFile(String baseData, SnarkManager manager) Validates the base file for torrent creation.(package private) StringwarBase()War-relative prefix under which static resources are served.private StringWarn icon for missing/unrecognized files.(package private) static List<Sorters.FileAndIndex> wrapFileList(File[] ls, Storage storage, long[] remainingArray, long[] previewArray, boolean skipPaddingDirs) Wraps a raw directory listing in Sorters.FileAndIndex entries carrying the precomputed per-file remaining/preview arrays, optionally hiding legacy padding directories.private voidwriteAddForm(PrintWriter out, HttpServletRequest req) Writes the HTML form for adding new torrents via URL or file upload.private voidwriteConfigForm(PrintWriter out, HttpServletRequest req) Writes the download and torrent settings form.private voidConfiguration page panels below the messages area.(package private) voidwriteHiddenInputs(PrintWriter out, HttpServletRequest req, String action) Hidden inputs for the nonce and parameters p, st, and sort.(package private) voidwriteHiddenInputs(StringBuilder buf, HttpServletRequest req, String action) Hidden inputs for the nonce and parameters p, st, and sort.private voidwriteMessages(PrintWriter out, boolean isConfigure, String peerString) Writes the logging messages to the HTML screenlog.private voidwritePageTail(PrintWriter out, boolean isConfigure) Page scripts and footer, shared by index and configuration pages.private voidwriteSeedForm(PrintWriter out, HttpServletRequest req, List<Tracker> sortedTrackers, List<TorrentCreateFilter> sortedFilters) Writes the HTML form for creating new torrents from local files.private voidWrites the torrent creation filter form.private booleanwriteTorrents(PrintWriter out, HttpServletRequest req, boolean canWrite) Writes the HTML representation of the torrents to the output stream.private voidwriteTorrentsSection(PrintWriter out, HttpServletRequest req, List<Tracker> sortedTrackers, List<TorrentCreateFilter> sortedFilters) Torrent table plus the add/create forms of the lower section.private voidwriteTrackerForm(PrintWriter out, HttpServletRequest req) Writes the tracker announce settings form.Methods inherited from class BasicServlet
addMimeMapping, addPaths, decodePath, doDelete, doOptions, doTrace, encodePath, getContent, getMimeType, loadMimeMap, passConditionalHeaders, sendData, setResourceBase, setWarBase, writeHeadersModifier and TypeMethodDescriptionprotected voidaddMimeMapping(String extension, String type) Add a MIME type mapping for an extension.protected static StringSimple version ofURIUtil.addPaths().protected static StringdecodePath(String path) Simple version ofURIUtil.decodePath().protected voiddoDelete(HttpServletRequest request, HttpServletResponse response) Handles HTTP DELETE requests.protected voiddoOptions(HttpServletRequest request, HttpServletResponse response) Handles HTTP OPTIONS requests.protected voiddoTrace(HttpServletRequest request, HttpServletResponse response) Handles HTTP TRACE requests.protected static StringencodePath(String path) Simple version ofURIUtil.encodePath(String).getContent(String pathInContext, long limit) Resource to serve, mapping a path to a resource.protected StringgetMimeType(String filename) The MIME type by filename extension.protected voidloadMimeMap(String resourcePath) Load MIME type mappings from a resource file.protected booleanpassConditionalHeaders(HttpServletRequest request, HttpServletResponse response, BasicServlet.HttpContent content) Check modification date headers.protected voidsendData(HttpServletRequest request, HttpServletResponse response, BasicServlet.HttpContent content) Sends the content to the client, handling range requests.protected voidsetResourceBase(File base) Files are served from here.protected voidsetWarBase(String base) Only paths starting with this in the path are served.protected voidwriteHeaders(HttpServletResponse response, BasicServlet.HttpContent content, long count) Write response headers for the content.Methods inherited from class HttpServlet
doHead, doPut, getLastModified, service, serviceMethods inherited from class GenericServlet
getInitParameter, getInitParameterNames, getServletConfig, getServletContext, getServletInfo, getServletName, init, log, log
Field Details
serialVersionUID
private static final long serialVersionUIDFixed serial version for the servlet.- See Also:
_contextPath
Context path, generally "/i2psnark"; set once inGenericServlet.init()._contextName
Context display name, generally "i2psnark"; set once in init()._manager
The manager holding this webapp's torrents._currentNonce
private long _currentNonceRotating CSRF nonce, rotates every 5 minutes._recentNonces
private final long[] _recentNoncesThe two nonces before the current one, still accepted for in-flight forms._lastRotation
private long _lastRotationWhen the current nonce was minted, ms since epoch; drives rotation.NONCE_ROTATION_MS
private static final long NONCE_ROTATION_MSForm nonces rotate every 5 minutes.- See Also:
_bridgeVersion
Version of the bundled I2PSnark Bridge XPI, read lazily from the war; null if unknown._bridgeUpdateLogged
private static volatile boolean _bridgeUpdateLoggedSet once when an outdated I2PSnark Bridge extension reported itself; one screen-log notice per webapp start.INFOHASH_PAREN
Splits a pasted info hash from a trailing parenthetical.STAT_DOWNLOADED
private static final int STAT_DOWNLOADEDCumulative stats array indices: [downloaded, uploaded, download rate, upload rate, peers, total size].- See Also:
STAT_UPLOADED
private static final int STAT_UPLOADEDSort key for the uploaded column.- See Also:
STAT_DOWNLOAD_RATE
private static final int STAT_DOWNLOAD_RATESort key for the download rate column.- See Also:
STAT_UPLOAD_RATE
private static final int STAT_UPLOAD_RATESort key for the upload rate column.- See Also:
STAT_PEERS
STAT_TOTAL_SIZE
private static final int STAT_TOTAL_SIZESort key for the total size column.- See Also:
HEX_PATTERN
Matches a hex info hash.BASE32_PATTERN
Matches a base32 name without the suffix._themePath
Web path of the active theme's resources; recomputed per request._resourcePath
Web path of static resources; set once in init(), never mutated per request._imgPath
Icon image base path derived from_themePath._lastAnnounceURL
Announce URL of the torrent being edited; preselects its tracker radio button.DEFAULT_NAME
Webapp name used in paths and config keys.- See Also:
PROP_CONFIG_FILE
WARBASE
HELLIP
static final char HELLIPEllipsis character used to truncate long names.- See Also:
PROP_ADVANCED
Config key for the console's advanced mode.- See Also:
RC_PROP_ENABLE_SORA_FONT
Config key for the console's Sora font option.- See Also:
_DATE_FMT1
Per-thread date format for the torrent list._DATE_FMT2
Per-thread date format including the time._DATE_FMT3
Per-thread date format for file timestamps.searchResults
private int searchResultsSearch results.cspNonce
String cspNonceCsp nonce.configForms
Settings form writer, which reads its settings back through this servlet's accessors.MAX_DISPLAYED_FILENAME_LENGTH
static final int MAX_DISPLAYED_FILENAME_LENGTHLongest file name shown before truncation.- See Also:
DOCTYPE
Document type line opening every page.- See Also:
TABLE_HEADER
Opening of the torrent list table.- See Also:
FOOTER
FOOTER_STANDALONE
The html footer of the standalone page.- See Also:
IFRAME_FORM
Hidden iframe that receives form posts.- See Also:
STREAM_MIN_TORRENT_ROWS
private static final int STREAM_MIN_TORRENT_ROWSMinimum visible rows before a torrent-list page renders in streamed mode. Torrent rows are heavy (badges, progress bars, ~1-2 KB each), so this gate sits lower than the file-table gate.- See Also:
STREAM_MIN_FILE_ROWS
private static final int STREAM_MIN_FILE_ROWSMinimum visible rows before a directory file table renders in streamed mode. File rows are lighter than torrent rows, so buffering stays worthwhile up to a higher count; below the gate a single buffered write keeps Content-Length on the directory page.- See Also:
STREAM_DRAIN_EVERY
private static final int STREAM_DRAIN_EVERYRows rendered per chunk in streamed mode; bounds the staging buffer near tens of KB.- See Also:
DIRECTORY_POST_ACTIONS
Command keys accepted byexecuteDirectoryPostAction(Snark, Map, String), in precedence order.POSTMAN_B64
Known postman tracker base64 announce, both old and new.- See Also:
POSTMAN_B64_NEW
Base64 destination of the Postman tracker's new address.- See Also:
BT_B32
CHUDO_B32
Base32 address of the Chudo tracker.- See Also:
CRYPT_B32
Base32 address of the Cryptopolis tracker.- See Also:
FREEDOM_B32
Base32 address of the Freedom tracker.- See Also:
ICU812_B32
Base32 address of the ICU812 tracker.- See Also:
LODIKON_B32
Base32 address of the Lodikon tracker.- See Also:
LYOKO_B32
Base32 address of the Lyoko tracker.- See Also:
ODIFT_B32
Base32 address of the Odift tracker.- See Also:
OMITRACK_B32
Base32 address of the Omirack tracker.- See Also:
OTDG_B32
Base32 address of the OnionTracker tracker.- See Also:
POSTMAN_B32_NEW
Base32 address of the Postman tracker's new address.- See Also:
R4SAS_B32
Base32 address of the R4SAS tracker.- See Also:
SKANK_B32
Base32 address of the Skank tracker.- See Also:
SIMP_B32
Base32 address of the SIMP tracker.- See Also:
THEBLAND_B32
Base32 address of The Bland tracker.- See Also:
SIGMA_B32
Base32 address of the Sigma tracker.- See Also:
ACTIX_B32
Base32 address of the Actix tracker.- See Also:
FATTYDOVE_B32
Base32 address of the FattyDove tracker.- See Also:
LOCALCACHE_B32
Base32 address of the LocalCache tracker.- See Also:
OBSERVATIONS_B32
Base32 address of the Observations tracker.- See Also:
PUBLIC_B32
Base32 address of the Public tracker.- See Also:
YETANOTHER_B32
Base32 address of the YetAnother tracker.- See Also:
KNOWN_TRACKERS
Known tracker announce keys (base64 postman blobs and base32 hostnames) mapped to their display names. Package-visible for testing. Matched literally - entries are plain strings, not regexes.
Constructor Details
I2PSnarkServlet
public I2PSnarkServlet()Constructor called by the servlet container; all setup is deferred to init().
Method Details
getNonce
private long getNonce()Current CSRF nonce, rotating every 5 minutes.- Returns:
- the current CSRF nonce, rotated every NONCE_ROTATION_MS
isValidNonce
Validate nonce against current and recent nonces (backward compatibility).- Parameters:
nonce- the nonce to validate- Returns:
- true if valid
allowOrigin
Validate Origin header for POST requests. Allows requests with matching Origin (same-origin), or no Origin header. Rejects cross-origin POST requests to prevent CSRF attacks.- Parameters:
request- the HTTP request- Returns:
- true if allowed
manager
SnarkManager manager()The torrent manager behind this servlet.- Returns:
- the SnarkManager holding the torrents this servlet renders
contextPath
String contextPath()The context path this servlet is mounted under.- Returns:
- the context path, always starting with '/'
contextName
String contextName()The name identifying this instance in config and titles.- Returns:
- the context name, defaulting to "i2psnark"
resourcePath
String resourcePath()Prefix for links to resources bundled in the war.- Returns:
- the context path plus WARBASE
warBase
String warBase()War-relative prefix under which static resources are served.- Returns:
- the resource prefix, "/.res/"
context
I2PAppContext context()The I2P context this servlet runs in.- Returns:
- the app context passed to init()
configForms
I2PSnarkConfigure configForms()The settings form writer.- Returns:
- the writer backing the /configure pages
writeConfigForm
Writes the download and torrent settings form.- Parameters:
out- where to write the formreq- the request being served- Throws:
IOException- if the write fails
writeTorrentCreateFilterForm
private void writeTorrentCreateFilterForm(PrintWriter out, HttpServletRequest req) throws IOException Writes the torrent creation filter form.- Parameters:
out- where to write the formreq- the request being served- Throws:
IOException- if the write fails
writeTrackerForm
Writes the tracker announce settings form.- Parameters:
out- where to write the formreq- the request being served- Throws:
IOException- if the write fails
init
Initialize the servlet.- Specified by:
initin interfaceServlet- Overrides:
initin classBasicServlet- Parameters:
cfg- the servlet config- Throws:
ServletException- if initialization fails
destroy
public void destroy()Destroy the servlet.- Specified by:
destroyin interfaceServlet- Overrides:
destroyin classGenericServlet
getResource
We override this to set the file relative to the storage directory for the torrent. Deliberately unsynchronized: this runs for every snark request, and the only shared field it reads (_resourceBase) is volatile.- Overrides:
getResourcein classBasicServlet- Parameters:
pathInContext- should always start with /- Returns:
- the resolved file, or null if it does not exist
resolveTorrentPath
The on-disk location of a path within a torrent. While an incomplete download is staged in the temp dir, the data-directory tree may not exist yet, so the path falls back to the staging tree, which mirrors the data-directory layout.- Parameters:
storage- the torrent's storagepathInTorrent- the path within the torrent, "/" or empty for the root- Returns:
- the physical file
doGet
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException Handle what we can here, calling super.doGet(HttpServletRequest, HttpServletResponse)for the rest.- Overrides:
doGetin classBasicServlet- Throws:
ServletExceptionIOException
doPost
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException Handle what we can here, calling super.doPost(HttpServletRequest, HttpServletResponse)for the rest.- Overrides:
doPostin classBasicServlet- Parameters:
request- the HTTP requestresponse- the HTTP response- Throws:
ServletException- if a servlet error occursIOException- if an I/O error occurs
isAdvanced
public boolean isAdvanced()Returns whether advanced mode is enabled in the router console.- Returns:
- true if advanced mode is enabled
useSoraFont
public boolean useSoraFont()Returns whether the Sora display font should be used.- Returns:
- true if the Sora font is enabled or running in standalone mode
doGetAndPost
private void doGetAndPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException Handle what we can here, calling super.doGet() or super.doPost() for the rest. Routing, in order: gatekeeping (Origin check on POST, CSP, static WARBASE);handleAjaxRequest(String, boolean, String, HttpServletRequest, HttpServletResponse)for the XHR fragment endpoints; /_add; /magnet;handleUnmanagedPath(HttpServletRequest, HttpServletResponse, String, String)for listings, playlists and passthrough;handleFormSubmission(HttpServletRequest, HttpServletResponse, String, String)for nonce'd POST actions; then page assembly - head, navbar, search scaffolding, eitherwriteConfigurePanels(PrintWriter, HttpServletRequest)orwriteTorrentsSection(PrintWriter, HttpServletRequest, List, List), andwritePageTail(PrintWriter, boolean).- Parameters:
req- the request whose method, servlet path and parameters select the handlerresp- the response the selected handler writes to- Throws:
ServletException- if a passthrough to the container's doGet/doPost or a sendError failsIOException- if writing or flushing the response fails
isAjaxPath
The two XHR fragment endpoints polled by the console JS.- Parameters:
path- servlet path after the context, may be null- Returns:
- true if the path is one of the polled fragments
isIndexPath
Whether path is the torrent list landing page.- Parameters:
path- servlet path after the context, may be null- Returns:
- true for "", "/", or "index.jsp"
isUnmanagedPath
Paths that bypass normal page rendering and are answered by handleUnmanagedPath: everything outside the index page(s), the POST target, and the configuration UI.- Parameters:
path- servlet path after the context, may be nullisIndex- whether path is the torrent list landing pageisConfigure- whether the request selected the configuration UI- Returns:
- true if handleUnmanagedPath should answer the request
handleAjaxRequest
private boolean handleAjaxRequest(String path, boolean isConfigure, String peerString, HttpServletRequest req, HttpServletResponse resp) throws IOException Serves the XHR fragment endpoints; unknown paths are ignored so the caller's fall-through routing stays in charge.- Parameters:
path- servlet path after the context, may be nullisConfigure- whether the request selected the configuration UIpeerString- the peer parameter to carry into message rendering, may be nullreq- the HTTP requestresp- the HTTP response- Returns:
- true if the request was handled here
- Throws:
IOException- if writing the response fails
handleUnmanagedPath
private void handleUnmanagedPath(HttpServletRequest req, HttpServletResponse resp, String method, String path) throws ServletException, IOException Answers everything outside the managed pages: torrent directory listings (with optional playlist export) under trailing-slash paths, and container delegation for the rest.- Parameters:
req- the request whose path info and playlist/sort parameters drive the listingresp- the response written tomethod- the HTTP method; GET/HEAD/POST delegate to the container, anything else gets 405path- the servlet path; a trailing slash selects the directory listing branch- Throws:
ServletException- if a passthrough to the container's doGet/doPost or a sendError failsIOException- if writing the listing or an error page fails
handleFormSubmission
private boolean handleFormSubmission(HttpServletRequest req, HttpServletResponse resp, String method, String peerString) throws IOException Dispatches a nonce-bearing form submission to its action and finishes with the P-R-G redirect (or G-R-G to hide params from the address bar).- Parameters:
req- the submitted form request; its nonce parameter decides whether this method takes overresp- the response redirected once the action has runmethod- the HTTP method; only POST, or GET with action=Clear, is acceptedpeerString- the peer query string carried into the redirect- Returns:
- true if a form was submitted and the response is complete; false when there is no nonce and normal rendering should proceed
- Throws:
IOException- if the redirect response cannot be sent
appendSearchForm
Renders the search form when multiple torrents exist; hidden until realtimeSearch.js activates it, functional without JS via GET submit.- Parameters:
buf- destination for the form markup; nothing is appended when one or fewer torrents existreq- the request whose search parameter pre-fills the input
writeConfigurePanels
Configuration page panels below the messages area.- Parameters:
out- writer for the configuration page bodyreq- the request passed through to the config, filter and tracker forms- Throws:
IOException- if writing the forms fails
writeTorrentsSection
private void writeTorrentsSection(PrintWriter out, HttpServletRequest req, List<Tracker> sortedTrackers, List<TorrentCreateFilter> sortedFilters) throws IOException Torrent table plus the add/create forms of the lower section.- Parameters:
out- writer for the torrents page bodyreq- the request passed through to the torrent table and the add/create formssortedTrackers- trackers offered in the create form's announce listsortedFilters- torrent-create filters offered in the create form- Throws:
IOException- if writing the table or forms fails
writePageTail
Page scripts and footer, shared by index and configuration pages.- Parameters:
out- writer positioned just before the footerisConfigure- true on the configuration page, which omits the toggleLinks and toggleAddCreate scripts- Throws:
IOException- if writing the scripts or footer fails
renderHead
private String renderHead(HttpServletRequest req, boolean isConfigure, boolean isIndex, boolean noCollapse, boolean collapsePanels, boolean showStatusFilter, String peerString, String lang, int delay, int pageSize) Renders the full <head> section of the main HTML page.- Parameters:
req- the request being rendered; currently unusedisConfigure- true for the configuration page, which skips the torrent-list scripts and preloadsisIndex- true for the main index page, which adds the click and alert scriptsnoCollapse- true forces nocollapse.css regardless of the collapsePanels settingcollapsePanels- whether panels are collapsible per the current settingsshowStatusFilter- true adds the filter-bar script preloadspeerString- the peer query string embedded in the noscript refresh redirectlang- the UI language code; zh, ja and ko get a larger-font stylesheetdelay- auto-refresh interval in seconds; > 0 adds a noscript meta-refresh, floored at 60pageSize- torrents per page, exported to JS as snarkPageSize- Returns:
- the doctype, the opening <html> tag and the complete <head> section
setHTMLHeaders
Handles the standard HTTP headers for all HTML pages.- Parameters:
resp- the HttpServletResponse object to which headers will be addedcspNonce- the nonce value for Content Security Policy (CSP)allowMedia- whether to allow media sources in CSP
setXHRHeaders
Cross-Origin Resource Sharing (CORS) and Content Security Policy (CSP) headers for XMLHttpRequest (XHR) responses.- Parameters:
resp- the HttpServletResponse object to which headers will be addedcspNonce- the nonce value for the Content Security Policy (CSP)allowMedia- indicates whether media sources should be allowed in CSP
screenLogStamp
Cheap change-detection stamp for the screen log, emitted with every xhr1 refresh payload so the client can skip the xhrscreenlog.html round trip while the log is unchanged. Combines the last message id (which advances on every add) with the list size (which moves on clears and cap-driven trims), so both growth and shrinkage are detected without rendering anything.- Returns:
- "lastMessageId:messageCount", or "0:0" when the log is empty
emitGraphData
Emits the bandwidth graph element for xhr1 payloads. The client passes its last seen sample version as the "gv" parameter; the full sample CSV travels only when the client is behind, so steady-state ticks cost a few bytes.- Parameters:
req- the refresh request, may carry a "gv" parameterout- the PrintWriter to write the element to
writeMessages
private void writeMessages(PrintWriter out, boolean isConfigure, String peerString) throws IOException Writes the logging messages to the HTML screenlog.- Parameters:
out- the PrintWriter to which the HTML output will be writtenisConfigure- a boolean indicating whether the current page is the configuration pagepeerString- a string containing the peer parameters for the URL- Throws:
IOException- if an I/O error occurs while writing to the output stream
writeTorrents
private boolean writeTorrents(PrintWriter out, HttpServletRequest req, boolean canWrite) throws IOException Writes the HTML representation of the torrents to the output stream. This method generates the HTML structure for displaying torrents, including headers, sorting options, pagination controls, and the torrent list itself. It also updates the statistics array with aggregated torrent data. Output is gated by row count: pages with fewer than STREAM_MIN_TORRENT_ROWS visible rows stage the whole table into one buffer written in a single call, larger pages stream rows to the writer as today. Markup order is identical in both modes. Note the page scaffold upstream of this method is flushed before the gate is evaluated, so buffered mode does not restore Content-Length here.- Parameters:
out- the PrintWriter to which the HTML output will be writtenreq- the HttpServletRequest containing the request parameterscanWrite- a boolean indicating whether the data directory is writable- Returns:
- true if the current page is the first page of the torrent list
- Throws:
IOException- if an I/O error occurs while writing to the output stream
appendSnarkHeader
private String appendSnarkHeader(HttpServletRequest req, List<Snark> snarks, int start, int pageSize, String filterParam, String peerParam, String currentSort, String contextPath) Builds the HTML table header row for the torrent list display, including sortable column headers, peer toggling links, and activity indicators.Dispatcher only: prepares request-derived inputs into a SortHeaderContext plus an activity scan, then delegates each column to its own builder so per-column markup stays independently reviewable.
- Parameters:
req- the HttpServletRequest containing the current request parameterssnarks- the list of torrent objects currently shown or filteredstart- the starting index of the current page slice within the torrent listpageSize- the maximum number of torrents displayed per pagefilterParam- the current filter parameter controlling torrent visibilitypeerParam- the current peer parameter controlling peer display togglingcurrentSort- the current sorting parameter for the torrent listcontextPath- the context path prefix for constructing URLs- Returns:
- a String containing the fully constructed HTML for the torrent table header row
scanTorrentActivity
private I2PSnarkServlet.TorrentActivityScan scanTorrentActivity(List<Snark> snarks, int start, int pageSize, int total) Scans the page slice for peer/rate activity, exiting early once every flag is set. Extracted from appendSnarkHeader; write-only counters that were computed here previously are gone.- Parameters:
snarks- full sorted liststart- first row of the rendered slicepageSize- rows per pagetotal- list size bounding the slice- Returns:
- flags for the slice, never null
nextStatusSort
Next value of the Status column sort cycle: toggles status asc/desc, and in multi-destination mode continues into status+pool asc/desc before returning to status desc. Unknown keys restart at desc.- Parameters:
currentSort- current sort key, may be nullpoolSort- true when multi-destination mode is active- Returns:
- the next sort key, never null
nextTorrentNameTypeSort
Name/type ladder for the torrent column. Unlike the directory-page cycle (nextNameTypeSort(String)) the fallback after foreign keys restarts at name ascending ("1"), not unsorted - both behaviors are pinned by tests.- Parameters:
currentSort- current sort key, may be null- Returns:
- the next sort key, never null
nextRXSort
nextTXSort
appendStatusHeader
private void appendStatusHeader(StringBuilder buf, I2PSnarkServlet.SortHeaderContext hc, boolean poolSort, String txtStatus) Status column: sortable always; pool-aware vianextStatusSort(String, boolean).- Parameters:
buf- destination for the <th> markuphc- shared request-derived inputs: request, path, sort state and query partspoolSort- true when multi-destination mode is active, which extends the sort cycle with the pool keystxtStatus- localized label for the status column
appendPeerToggleHeader
private void appendPeerToggleHeader(StringBuilder buf, I2PSnarkServlet.SortHeaderContext hc, String peerParam, boolean isConnected, boolean noSnarks, I2PSnarkServlet.TorrentActivityScan scan) Peer-count column: renders the show/hide peers toggle when connected with peers present; empty cell otherwise.- Parameters:
buf- destination for the <th> markuphc- shared request-derived inputs: request, path, sort state and query partspeerParam- the p request parameter when peers are currently shown, null when they are hiddenisConnected- the router is connected to the I2P networknoSnarks- no torrents are loadedscan- activity flags computed from the listed torrents
appendNameTypeHeader
private void appendNameTypeHeader(StringBuilder buf, I2PSnarkServlet.SortHeaderContext hc, String txtTorrent) Torrent name/type column: cycles vianextTorrentNameTypeSort(String); active-state detection mirrors the five name/type keys.- Parameters:
buf- destination for the <th> markuphc- shared request-derived inputs: request, path, sort state and query partstxtTorrent- localized label for the torrent name column
appendEtaHeader
private void appendEtaHeader(StringBuilder buf, I2PSnarkServlet.SortHeaderContext hc, String txtETA, boolean isConnected, boolean noSnarks, I2PSnarkServlet.TorrentActivityScan scan) ETA column: sortable only while something on the page is downloading.- Parameters:
buf- destination for the <th> markuphc- shared request-derived inputs: request, path, sort state and query partstxtETA- localized label for the ETA columnisConnected- the router is connected to the I2P networknoSnarks- no torrents are loadedscan- activity flags computed from the listed torrents; the column is sortable only when isDownloading is set
appendRxHeader
private void appendRxHeader(StringBuilder buf, I2PSnarkServlet.SortHeaderContext hc, String txtRX, boolean noSnarks) RX column: four-state cycle vianextRXSort(String)whenever the list is sortable; empty cell otherwise.- Parameters:
buf- destination for the <th> markuphc- shared request-derived inputs: request, path, sort state and query partstxtRX- localized label for the downloaded-bytes columnnoSnarks- no torrents are loaded
appendRateDownHeader
private void appendRateDownHeader(StringBuilder buf, I2PSnarkServlet.SortHeaderContext hc, String txtRXRate, String txtRX, String peerParam, boolean isConnected, boolean noSnarks, I2PSnarkServlet.TorrentActivityScan scan) Download-rate column: sortable only while downloading; direction icon reflects the current key.- Parameters:
buf- destination for the <th> markuphc- shared request-derived inputs: request, path, sort state and query partstxtRXRate- localized label for the download-rate columntxtRX- localized label for the downloaded-bytes column, used in the sort tooltippeerParam- the p request parameter when peers are shown, null when they are hiddenisConnected- the router is connected to the I2P networknoSnarks- no torrents are loadedscan- activity flags computed from the listed torrents; the column is sortable only when isDownloading is set
appendTxHeader
TX column: four-state cycle vianextTXSort(String)whenever the list is sortable; empty cell otherwise.- Parameters:
buf- destination for the <th> markuphc- shared request-derived inputs: request, path, sort state and query partstxtTX- localized label for the uploaded-bytes column
appendRateUpHeader
private void appendRateUpHeader(StringBuilder buf, I2PSnarkServlet.SortHeaderContext hc, String txtTXRate, boolean isConnected, boolean noSnarks, I2PSnarkServlet.TorrentActivityScan scan) Upload-rate column: sortable only while uploading; ascending icon when currently on "9" (note the inverted default versus rateDown).- Parameters:
buf- destination for the <th> markuphc- shared request-derived inputs: request, path, sort state and query partstxtTXRate- localized label for the upload-rate columnisConnected- the router is connected to the I2P networknoSnarks- no torrents are loadedscan- activity flags computed from the listed torrents; the column is sortable only when isUploading is set
appendActionsHeader
private void appendActionsHeader(StringBuilder buf, List<Snark> snarks, boolean isConnected, boolean noSnarks, String txtStartAll, String txtStopAll, String txtStopAllTitle, String txtStartAllTitle, String txtStartStoppedTitle) Action column: Stop All always when connected; Start All variants depending on whether any listed torrent is stopped.- Parameters:
buf- destination for the <th> markupsnarks- the torrents on the page; the first stopped one triggers the Start All buttonisConnected- the router is connected to the I2P networknoSnarks- no torrents are loadedtxtStartAll- label of the Start All buttontxtStopAll- label of the Stop All buttontxtStopAllTitle- title attribute for the Stop All buttontxtStartAllTitle- title attribute when no torrent is stoppedtxtStartStoppedTitle- title attribute when a stopped torrent exists
appendSortHeader
private void appendSortHeader(StringBuilder buf, I2PSnarkServlet.SortHeaderContext hc, String newSort, String cssClass, String iconName, String title, boolean showSort, boolean currentSortMatches, boolean isDescending) Appends a sortable table header cell including sort icons and links. Shows ascending or descending icon only if this header matches current sorting.- Parameters:
buf- the StringBuilder used to append HTML contenthc- shared request-derived inputs (request, path, sort state, query parts)newSort- the sort parameter value to link to for toggling sortingcssClass- CSS class to apply to the <th> elementiconName- icon identifier for renderingtitle- localized title text for the header cellshowSort- if true, render sorting link and icons; otherwise render plain headercurrentSortMatches- true if this header corresponds to the current sort parameter (active sorted column)isDescending- true if the current sorting direction for this header is descending
multiDestActive
boolean multiDestActive()Whether multi-destination mode is active: enabled in the config with at least one active destination. Gates everything pool-related - the per-row destination badges, status+pool sorting, and the clamp that keeps StatusPoolComparator out of single-dest requests.- Returns:
- true when multi-dest mode is in use
appendDebugRow
Renders the DHT debug row as the second row of the snark footer, hidden unless debug mode (?p=2) is active. Kept inside the single #snarkFoot tfoot so browsers lay it out below the totals row, as multiple tfoot elements render out of order.- Parameters:
out- target for the HTMLdht- the DHT, or null if not runningpeerParam- the p request parameter; the row is visible only when it equals 2- Throws:
IOException- if writing the row fails
buildLink
Composes a link URL from a path, a servlet-generated query string, and extra query text, choosing the '?'/'&' separators by inspection rather than by caller-supplied guesses about the raw request. Robust against every historical producer form: qs may begin with '?' (getQueryString contract), be bare ("k=v"), or be empty; extra may be empty or carry multiple "&"-joined pairs without a leading mark. Replaces six hand-rolled joins whose separator logic silently broke sort/filter persistence on parameterless page loads.- Parameters:
path- leading URL path including trailing '/'qs- query portion fromgetQueryString(HttpServletRequest, String, String, String, String): '', 'k=v' or '?k=v...'extra- additional pairs joined by '&', no leading mark, may be empty- Returns:
- composed URL, never null
renderFilterBar
Renders the torrent filter bar with links for filtering and searching torrents. Constructs URLs preserving existing query parameters except the current filter, then appends updated filter criteria. Displays badges with counts for some filters.- Parameters:
out- the PrintWriter to write the generated HTML outputreq- the current HttpServletRequest providing query parameters and URL- Throws:
IOException- if an I/O error occurs during writing to the output stream
buildFilterLink
private String buildFilterLink(String baseUrl, String filterId, boolean visible, String title, String badgeText) Builds an HTML filter link anchor element with an optional badge and visibility toggle.- Parameters:
baseUrl- the base URL to which the filter id is appended as a parameterfilterId- the id and filter name used in the linkvisible- whether the link should be visible or hidden (via CSS)title- the display text for the filter linkbadgeText- optional badge content to display inside the link- Returns:
- the constructed HTML string of the filter link
buildSimpleFilterLink
Builds a simple HTML filter link anchor element with a badge but no visibility toggle.- Parameters:
baseUrl- the base URL to which the filter id is appended as a parameterfilterId- the id and filter name used in the linktitle- the display text for the filter linkbadge- the badge HTML to append inside the link- Returns:
- the constructed HTML string of the filter link
search
Search torrents for matching terms.- Parameters:
search- non-nullsnarks- torrents to search; not modified- Returns:
- null if no valid search, or matching torrents in same order, empty if no match
writeHiddenInputs
Hidden inputs for the nonce and parameters p, st, and sort.- Parameters:
out- writes to itreq- the HTTP request, read for the p, st, sort and search parametersaction- if non-null, add it as the action
writeHiddenInputs
Hidden inputs for the nonce and parameters p, st, and sort. Emitted in a fixed order; absent request values are omitted.- Parameters:
buf- appends to itreq- the HTTP request, read for the p, st, sort and search parametersaction- if non-null, add it as the action
appendHiddenInput
Append a single hidden form input.- Parameters:
buf- destination for the input markupname- the form field name, written unquotedvalue- the field value, sanitized per escesc- true to HTML-escape the value (free-text fields such as search), false to strip HTML (numeric and enum fields)
normalizeSortParam
Normalize a human-readable sort parameter to its legacy numeric form, e.g. "pool-desc" to "-13", so readable URLs survive header cycling, hidden inputs and query-string rebuilds. Numeric and unrecognized values pass through unchanged.- Parameters:
sort- the raw sort parameter, or null- Returns:
- the normalized sort parameter, or null
getQueryString
private static String getQueryString(HttpServletRequest req, String p, String st, String so, String search) Query string with an optional search override. Parameters are emitted in fixed p, sort, st, search order. Only values that are exactly signed integers are emitted, so a free-text search override never round-trips through these URLs.- Parameters:
req- the current request, for inherited valuesp- page override, or null to inherit and sanitize from the requestst- start-index override, or null to inherit and sanitizeso- sort override, or null to inherit and normalizesearch- search override, or null to inherit and HTML-escape- Returns:
- the query string, beginning with '?' or empty
appendQueryParam
private static void appendQueryParam(StringBuilder buf, HttpServletRequest req, String name, String override) Append one query pair to buf if it resolves to an emittable value. A null override inherits the value from the request, applying the per-name sanitization the legacy map-based implementation used: sort is normalized, p/sort/st are HTML-stripped, search is HTML-escaped. Explicit overrides are trusted as caller-provided constants. Emission requires an exact signed integer, matching the validation applied when such links are later parsed.- Parameters:
buf- destination buffer, prefix '?' or '&' chosen by its statereq- the current request, for inherited valuesname- parameter name to emitoverride- caller-supplied value, or null to inherit
paginator
private void paginator(PrintWriter out, HttpServletRequest req, int start, int pageSize, int total, String filter, boolean noThinsp, boolean isForm, boolean searchActive, int searchLength) throws IOException Renders the page navigation controls with visibility handling.- Parameters:
out- the PrintWriter to write HTML output toreq- the HttpServletRequest containing request parametersstart- the starting index of the current page viewpageSize- the number of items per pagetotal- the total number of items availablefilter- the current filter parameter stringnoThinsp- flag indicating special rendering for certain browsersisForm- whether the page is rendering as a form (affects visibility logic)searchActive- whether a search is currently active on the pagesearchLength- length of the active search string- Throws:
IOException- if an error occurs writing output
processRequest
Process HTTP request to handle torrent-related actions. Delegates to specific handlers based on the action parameter.- Parameters:
req- the request whose action parameter selects the handlerresp- the response, used by handlers that write it directly- Returns:
- true if a handler fully consumed the response and the caller must not render; false to continue with normal rendering
extractAction
Extracts the action parameter from the request. Checks "action" parameter and fallback to keys starting with "do_".- Parameters:
req- the HTTP request- Returns:
- the extracted action or null if none found
handleAdd
Handles the "Add" action, processes file uploads or URLs to add torrents.- Parameters:
req- the HTTP request
handleBrowserApiAdd
private void handleBrowserApiAdd(HttpServletRequest req, HttpServletResponse resp) throws IOException Nonce-free browser API: adds a magnet link, torrent URL, info hash, or local torrent file path. POST only. Authorized when the browser API is enabled and the client is loopback, in the configured allowed hosts list, or presents a valid API key. Replies with a single text/plain status line.- Parameters:
req- the HTTP requestresp- the HTTP response- Throws:
IOException- on write failure
handleMagnetPage
The page the browser opens when a magnet: link is handed to the I2PSnark Bridge extension (registered via protocol_handlers in the extension manifest). The page itself performs no server-side action. The external script magnetHandler.js reads the magnet from the URL, POSTs it to the browser API /_add on the same origin, dispatches a CustomEvent the extension's content script forwards to the background script for a browser notification, and closes the tab immediately. The page body is intentionally blank so the tab the protocol handler opens is never noticed; the result is only shown in the browser notification.The magnet arrives in the URL, so the nofilter_ parameter name is required: the XSS filter strips '&' from filtered parameter values, and every real magnet link contains '&'.
GET only; the existing /_add authorization applies to the actual add.
- Parameters:
req- the HTTP requestresp- the HTTP response- Throws:
IOException- on write failure
buildBridgeMetaTag
The meta element advertising the base URL of the I2PSnark webapp that served this page, so the I2PSnark Bridge extension's content script can discover the exact origin + context path (host, port, https) and route subsequent magnet: handoffs to it. This is authoritative even when the context path or listening port differs from the extension's manifest default (e.g. standalone I2PSnark on port 8002, custom console port).- Parameters:
baseUrl- the webapp base URL, e.g. http://127.0.0.1:8002/i2psnark- Returns:
- a single HTML meta line, or empty string when no URL is available
browserApiAuthorized
Whether the browser API request is authorized. Requires the API to be enabled and the client to be loopback, on the allowed hosts list, or to present the configured API key.- Parameters:
req- the request, for the client address and apiKey parameter- Returns:
- true if the request may use the browser API
browserApiAuthorized
public static boolean browserApiAuthorized(boolean enabled, boolean hostAllowed, String providedKey, String configuredKey) Pure decision function for browser API authorization (unit-testable): requires the API to be enabled and the client to be an allowed host or to present the configured API key.- Parameters:
enabled- the browser API enable flaghostAllowed- whether the client address is loopback or on the allowlistprovidedKey- the apiKey request parameter, may be nullconfiguredKey- the configured API key, may be null or empty- Returns:
- whether the request is authorized
browserApiName
Validate the browser API payload and extract a display name for the OK reply. Mirrors the formats accepted byhandleAddURL(String, File, RequestWrapper).- Parameters:
url- the URL, magnet, info hash, or file path- Returns:
- a display name, or null if unsupported
handleAddFile
Handles adding a torrent from an uploaded file.- Parameters:
newFile- filename from uploadtorrentDir- directory where uploaded .torrent files are keptdataDir- data directory where torrents are storedreqw- wrapped request for accessing multipart inputs
handleAddURL
Handles adding a torrent from a URL or magnet link.- Parameters:
newURL- the URL or magnet link stringdataDir- directory the new torrent's files are created underreqw- the wrapped request, read for the nofilter_ parameters
isValidHexInfoHash
Validates if a string is a valid 40-hex character info hash.- Parameters:
s- candidate v1 info hash: exactly 40 hex characters- Returns:
- whether valid hex info hash
isValidBase32InfoHash
Validates if a string is a valid 32-base32 character info hash.- Parameters:
s- candidate v1 info hash: exactly 32 base32 characters- Returns:
- whether valid base32 info hash
isValidV2InfoHash
Validates if string is version 2 hex multihash (68 characters starting with "1220").- Parameters:
s- candidate v2 info hash: 68 hex characters starting with "1220"- Returns:
- whether valid v2 info hash
handleAddFromFilePath
resolveTorrentByToken
Resolves a short action token to its torrent by unique-prefix match over the loaded torrents' base64 info-hash names. Ambiguous or unknown tokens return null, making stale submissions a safe no-op.- Parameters:
token- the token extracted from a submitted control name- Returns:
- the matching Snark, or null when none or several match
handleStop
Handles the "Stop_" action to stop a torrent by action token.- Parameters:
action- the tracker action to perform, as submitted by the form string starting with "Stop_"
handleStart
Handles the "Start_" action to start a torrent by action token.- Parameters:
action- the tracker action to perform, as submitted by the form string starting with "Start_"
handleRemove
Handles the "Remove_" action to remove a torrent by action token.- Parameters:
action- the action string starting with "Remove_"
unlinkTorrentFile
Unlinks a torrent's .torrent file, reporting the outcome as user messages. Magnet torrents (no metainfo) are deleted outright, since for them the .torrent file is the data.Shared by the Remove and Delete actions so both report identical messages for identical outcomes.
- Parameters:
snark- the torrent whose .torrent file should be removed- Returns:
- true when no .torrent file remains, so the caller may proceed to remove downloaded data; false when the torrent is still present (magnet deleted, or the file could not be removed)
handleDelete
Handles the "Delete_" action to delete a torrent and its data by action token.- Parameters:
action- the action string starting with "Delete_"
handleSave
Handles saving configuration updates.- Parameters:
req- the HTTP request with config parametersresp- the response, used only when an extension install redirect is issued- Returns:
- true if the response was fully handled (install redirect sent), false to continue with normal rendering
installBrowserApi
Installs the I2PSnark Bridge extension that forwards magnet links to the browser API endpoint. Called from the main config save when the install button was used; enables the API if it is off.The server writes no files: the browser is redirected to the bundled extension XPI, which opens the install prompt in the logged-in user's own browser session.
- Parameters:
req- the HTTP requestresp- the HTTP response- Returns:
- true if the response was fully handled (redirect sent)
getBridgeVersion
String getBridgeVersion()The version of the I2PSnark Bridge extension bundled in this war, read once from the XPI's manifest.json; null if it cannot be determined.- Returns:
- the bundled extension version, "" if the XPI carries none
browserApiBaseUrl
The console base URL for this request, e.g. http://127.0.0.1:7657/i2psnark (no trailing slash), used as the default endpoint of the installed handler.- Parameters:
req- the request whose URL and scheme identify the console origin- Returns:
- the scheme, host, port and context path, without a trailing slash
handleSaveTrackers
Handles saving tracker form updates.- Parameters:
req- the HTTP request
handleSaveCreateFilters
Handles saving torrent creation filter form updates.- Parameters:
req- the HTTP request
validateBaseFile
static I2PSnarkServlet.BaseFileValidationResult validateBaseFile(String baseData, SnarkManager manager) Validates the base file for torrent creation. Checks: not empty, exists, not .torrent, not duplicate, not in I2P dirs, not nested.- Parameters:
baseData- the raw base file path from requestmanager- the SnarkManager for context (data dir, existing torrents)- Returns:
- validation result with resolved File and error message (null if valid)
parseAnnounceParams
Parses announce URL and backup tracker URLs from the request. Recognized: "announceURL", "backup_*" parameters.- Parameters:
req- the HTTP request- Returns:
- parsed announce parameters, never null
buildAnnounceList
static I2PSnarkServlet.CreateAnnounceListResult buildAnnounceList(I2PSnarkServlet.AnnounceParams params, List<String> privateTrackers) Builds the tiered announce list from primary and backup URLs. Validates no mixing of private and public trackers.- Parameters:
params- parsed announce parametersprivateTrackers- the configured private tracker URLs- Returns:
- announce list result with tiered list and private flag, or error
parseCreateFilters
static List<TorrentCreateFilter> parseCreateFilters(HttpServletRequest req, Map<String, TorrentCreateFilter> filterMap) Parses the selected torrent creation filters from the request.- Parameters:
req- the HTTP requestfilterMap- the available filters from manager- Returns:
- list of selected filters (never null)
handleCreate
Handles creating a new torrent from provided base file or directory.- Parameters:
req- the HTTP request
handleStopAll
Handles stopping all torrents or search-filtered torrents.- Parameters:
req- the HTTP request with "search" parameter
handleStartAll
Handles starting all torrents or search-filtered torrents.- Parameters:
req- the HTTP request with "search" parameter
handleClearMessages
Handles clearing messages by id.- Parameters:
req- the HTTP request with "id" parameter
sendRedirect
private void sendRedirect(HttpServletRequest req, HttpServletResponse resp, String p) throws IOException Redirect a POST to a GET (P-R-G), preserving the query string. The query string must only contain the numeric params thatgetQueryString(HttpServletRequest, String, String, String, String)emits, so the redirect target can never be an attacker-supplied URL.- Parameters:
req- request whose URL supplies the redirect targetresp- response the 302 is written top- the query string, may be null or empty- Throws:
IOException- on write failure
processTrackerForm
Process tracker form submission.- Parameters:
action- the tracker action to perform, as submitted by the formreq- the request carrying the submitted tracker parameters
processTorrentCreateFilterForm
Process torrent create filter form submission.- Parameters:
action- the tracker action to perform, as submitted by the formreq- the request carrying the submitted tracker parameters
getSortedSnarks
Returns the list of torrents sorted according to the current request's sort parameter.- Parameters:
req- the HTTP request containing the "sort" parameter- Returns:
- a new sorted list of Snark instances
snarkMatchesFilter
Checks whether a torrent matches the given filter based on its status string.- Parameters:
s- the Snark torrent to checkfilter- the filter name (e.g., "active", "downloading", "stopped")snarkStatus- the status keyword string for the torrent- Returns:
- true if the torrent matches the filter, or if filter is null/empty
badgeInfo
Look up (or compute) the badge values for a torrent. The base64 destination encoding is by far the most expensive part of building the badge, and pool-sorted rows repeat the same destinations, so results are cached per render in the context's cache.- Parameters:
rc- row context carrying the shared cachesnark- the torrent being rendered- Returns:
- never-null cached badge info
displaySnark
private void displaySnark(PrintWriter out, I2PSnarkServlet.RowContext rc, StringBuilder buf) throws IOException Displays a single snark (torrent) as an HTML table row, including optional peer rows. UpdatesI2PSnarkServlet.RowContext.statswith cumulative data (uploaded, downloaded, rates, peer counts, and size). Filtering is applied here: rows not matching the active filter contribute to stats but emit no HTML. Appends generated HTML to the provided StringBuilder buffer instead of writing directly to output, allowing batching and improved rendering performance.- Parameters:
out- the PrintWriter the completed row buffer is appended torc- per-row and per-render inputs; stats contents are updated in placebuf- scratch buffer reset by the caller between rows- Throws:
IOException- if an I/O error occurs during output operations
injectPoolBadge
Injects the multi-dest pool badge into the status cell HTML. The badge carries the sequential pool number (or D for dedicated) and the destination prefix as tooltip, inserted before the closing </td>.- Parameters:
statusHtml- the status cell inner HTML, modified by this callsnark- the torrent whose destination to displayrc- row context carrying the shared badge cache; must not be null- Returns:
- the status HTML with the pool badge injected
appendTorrentActionButton
private void appendTorrentActionButton(StringBuilder buf, String action, String token, Snark snark, String title) Append a Remove or Delete submit button for a torrent row. Both carry the JS-escaped torrent names consumed by the row's confirmation script.- Parameters:
buf- destination buffer for the row HTMLaction- action suffix appended to the request parameter nametoken- base64 info hash forming the parameter name with the actionsnark- the torrent the button acts ontitle- tooltip text describing what will be removed or deleted
classifyStatus
static I2PSnarkServlet.StatusKind classifyStatus(boolean allocating, boolean checking, boolean starting, boolean trackerProblems, boolean running, boolean complete, int curPeers, int knownPeers, boolean uploading, boolean downloading) Pure decision function mirroring the historical if/else cascade ofbuildStatusString(Snark, int, int, long, long, boolean, long, long, boolean), extracted so state classification can be tested without rendering. Branch order here is load-bearing: earlier states win, exactly as in the original cascade.- Parameters:
allocating- torrent is allocating disk spacechecking- torrent is being checked or recheckedstarting- start requested, tunnels not built yettrackerProblems- tracker unreachable for over an hour while idlerunning- torrent is neither stopped nor erroredcomplete- all pieces present (remaining or needed == 0)curPeers- connected peer countknownPeers- total peers known from trackers/DHT/PEXuploading- current upload rate above zerodownloading- current download rate above zero- Returns:
- the single display state for this torrent
buildStatusString
private I2PSnarkServlet.StatusResult buildStatusString(Snark snark, int curPeers, int knownPeers, long downBps, long upBps, boolean isRunning, long remaining, long needed, boolean noThinsp) Generates HTML status string and status code for a Snark based on its state and peer info. Classification is delegated toclassifyStatus(boolean, boolean, boolean, boolean, boolean, boolean, int, int, boolean, boolean); this method only renders.- Parameters:
snark- the torrent whose state and peers are being renderedcurPeers- current connected peersknownPeers- total known peersdownBps- current download rate in bytes per secondupBps- current upload rate in bytes per secondisRunning- true if the torrent is startedremaining- data left to downloadneeded- data needed for completionnoThinsp- spacing control flag- Returns:
- StatusResult containing the status HTML and status keyword
peerCountHtml
The peer-count cell shared by most status branches: current peers on the right, known peers in the swarm on the left.Called from
buildStatusString(Snark, int, int, long, long, boolean, long, long, boolean)per rendered row rather than hoisted to a single local, because four of its fourteen branches emit their own peer-count markup (em dash, or an empty cell) and would throw the shared value away.- Parameters:
curPeers- currently connected peersknownPeers- peers known from trackers, DHT, and PEXnoThinsp- true to substitute a plain slash for the thin-space pair- Returns:
- the peer-count cell markup, ending the preceding status cell
classifyPeerStatus
Determines the peer status (active/inactive with TX/RX flags).- Parameters:
peer- the peer to check- Returns:
- peer status with flags
appendPeerRow
private void appendPeerRow(StringBuilder buf, Peer peer, Snark snark, MetaInfo meta, boolean noThinsp) Appends HTML for a single peer row to the given StringBuilder.- Parameters:
buf- the StringBuilder to append topeer- the Peer object to rendersnark- the Snark (torrent) the peer belongs tometa- the MetaInfo of the torrent (may be null)noThinsp- whether to suppress thin space characters
renderPeerIdentity
Renders the peer identity/client section.- Parameters:
buf- the StringBuilder to append topeer- the peer to renderctx- the rendering context
renderPeerInactivity
Renders the peer inactivity bar if applicable.- Parameters:
buf- the StringBuilder to append toinactiveTime- the peer's inactive time in milliseconds
renderPeerProgress
Renders the peer progress bar or seed indicator.- Parameters:
buf- the StringBuilder to append topeer- the peer to renderctx- the rendering context- Returns:
- the completion percentage (101.0f if unknown)
renderDownloadRate
private void renderDownloadRate(StringBuilder buf, Peer peer, I2PSnarkServlet.PeerRowContext ctx, long needed) Renders the download rate cell.- Parameters:
buf- the StringBuilder to append topeer- the peer to renderctx- the rendering contextneeded- the needed length
renderUploadRate
private void renderUploadRate(StringBuilder buf, Peer peer, I2PSnarkServlet.PeerRowContext ctx, float pct, boolean isValid) Renders the upload rate cell.- Parameters:
buf- the StringBuilder to append topeer- the peer to renderctx- the rendering contextpct- the completion percentageisValid- whether meta is valid
getClientName
Returns a human-readable name of the client associated with the given Peer. <p>Most BitTorrent clients identify themselves using a 4-character prefix in the PeerID, often based on the client's identifier in the BitTorrent protocol handshake. These prefixes typically encode client-specific information (e.g., "-LT" for libtorrent, "-qB" for qBittorrent).</p> <p>This method maps known PeerID prefixes to client names using standardized conventions and attempts to extract client names from the handshake data if no match is found.</p> <p>Special cases: <ul> <li>I2PSnark PeerID starts with "AwMD" (Base64 encoding of \3\3\3)</li> <li>Handshake "v" field is used as a fallback to identify unknown clients</li> </ul>- Parameters:
peer- The Peer object to analyze.- Returns:
- A string representing the detected client name, or "Unknown" if undetermined.
formatSizeSpans
Formats a human-readable size string by wrapping unit characters (B, K, M, G, T) in HTML span tags with CSS classes for styling. <p> This method removes any "iB" substring and replaces each unit character with a corresponding closing and opening span tag sequence. The caller controls whether the left span is closed immediately by thecloseLeftSpanflag.- Parameters:
formattedSize- the size string already formatted (e.g. "123.4 MiB")closeLeftSpan- whether to append a closing </span> tag after each unit- Returns:
- the formatted string with added HTML span tags for styling unit characters
escapeJSString
Escape a string for embedding in an HTML attribute value that page scripts read back into JavaScript strings, e.g. the data-name and client attributes on the torrent action buttons. The backslash is escaped first so the generated escape sequences are not re-escaped, followed by the quote characters, the HTML-significant angle brackets and ampersand, and the line-break characters that cannot appear literally inside a JavaScript string literal. Output is ASCII-only. Escapes are emitted as JS short escapes for line breaks and two-digit hex escapes for everything else; they are deliberately spelled without the four-hex-digit unicode form because java's lexer processes such sequences before string escapes, even inside this comment. Not for use in URL or CSS contexts.- Parameters:
s- non-null string to escape- Returns:
- the escaped string, ASCII-only
thinsp
Thin-space markup, disabled if requested.- Parameters:
disable- true to emit a plain " / " separator instead of the thin-space markup- Returns:
- the separator markup, never null
getTrackerLinkUrl
Link to the details page if the tracker supports it. Start of anchor only; caller must add anchor text or img and close the anchor.- Parameters:
announce- the tracker announce URL, may be nullinfohash- the 20-byte info hash, url-encoded into the link- Returns:
- the opening anchor tag, or null if the tracker has no details page support
getTrackerLink
Full link to the details page with an image.- Parameters:
announce- the tracker announce URLinfohash- the 20-byte info hash, url-encoded into the link- Returns:
- the complete anchor with icon, or null when the tracker has no details page support
getShortTrackerLink
Full anchor to the home page or details page with shortened hostname as anchor text.- Parameters:
announce- the tracker announce URL; the scheme, path and port are stripped for the anchor textinfohash- the 20-byte info hash, used only for the details-page link- Returns:
- the complete anchor, never null
writeAddForm
Writes the HTML form for adding new torrents via URL or file upload.- Parameters:
out- the PrintWriter to write the HTML outputreq- the HTTP request containing query parameters- Throws:
IOException- if an I/O error occurs during writing
writeSeedForm
private void writeSeedForm(PrintWriter out, HttpServletRequest req, List<Tracker> sortedTrackers, List<TorrentCreateFilter> sortedFilters) throws IOException Writes the HTML form for creating new torrents from local files.- Parameters:
out- the PrintWriter to write the HTML outputreq- the HTTP request containing query parameterssortedTrackers- the list of available trackers for selectionsortedFilters- the list of available torrent create filters- Throws:
IOException- if an I/O error occurs during writing
isFirefoxFamilyUserAgent
Whether the given User-Agent header indicates a Firefox-family browser (Firefox, LibreWolf, Waterfox, Pale Moon, Tor Browser), which can install the I2PSnark Bridge extension. Unit-testable; other browsers get the installer-script fallback instead.- Parameters:
ua- the User-Agent header, may be null- Returns:
- true if the UA names Firefox
isWindowsUserAgent
Whether the given User-Agent header indicates Windows, which gets the PowerShell installer script instead of the shell one.- Parameters:
ua- the User-Agent header, may be null- Returns:
- true if the UA names Windows
addMagnet
_t
_t
_t
ngettext
formatSize
Format the file size.- Parameters:
bytes- the size in bytes- Returns:
- the size with a binary unit suffix and a 'B'
urlify
urlify
urlEncode
This is for a full URL. For a path only, use encodePath().Every caller embeds the result inside a double-quoted href attribute, so a literal quote would close the attribute and let the rest of the URL become new attributes - a stored XSS through any URL the user or a tracker supplied.
- Parameters:
s- the full URL to encode- Returns:
- the URL with ; & < > quote and brackets encoded, safe inside a double-quoted href attribute
cssLink
Generates a CSS link tag for the given filename.- Parameters:
filename- the CSS filename (e.g., "snark.css")themePath- the theme pathattributes- optional additional attributes (e.g., "id=snarkTheme")- Returns:
- complete link tag
shouldStreamTorrentRows
static boolean shouldStreamTorrentRows(int visibleRows) Whether a torrent list rendering visibleRows entries uses streamed output.- Parameters:
visibleRows- entries on the rendered page after filtering, non-negative- Returns:
- true once
STREAM_MIN_TORRENT_ROWSis reached
shouldStreamFileRows
static boolean shouldStreamFileRows(int visibleRows) Whether a directory file table rendering visibleRows entries uses streamed output.- Parameters:
visibleRows- entries actually rendered after filtering, non-negative- Returns:
- true once
STREAM_MIN_FILE_ROWSis reached
drainTo
Pushes staged markup to the response writer and empties the buffer, forcing bytes toward the client so large pages render progressively. Called only in streamed mode; buffered mode never drains.- Parameters:
out- non-null response writerbuf- staging buffer, emptied regardless of outcome- Returns:
- false if the client disconnected (writer error); callers should skip further drains, rendering continues only to keep counters and closing markup consistent
getListHTML
String getListHTML(File xxxr, String base, boolean parent, Map<String, String[]> postParams, String sortParam, PrintWriter out) throws IOExceptionModded heavily from the Jetty version in Resource.java, pass Resource as 1st param All the xxxResource constructors are package local so we can't extend them. Get the resource list as a HTML directory listing. Section map, in output order:- POST dispatch - torrent actions (priorities, comments, stop/start/ recheck, edit) via
handleDirectoryPost(Snark, Map); P-R-G means no rendering after a POST renderHeader(StringBuilder, String)- doctype, head, theme/font CSS, navbar- form open,
appendTorrentInfo(StringBuilder, Snark, String, String, boolean), displayTorrentEdit() appendResourceError(StringBuilder, File, String, String)when the path does not exist on disk- no-listing branch -
appendMediaSection(StringBuilder, String, String, String, boolean, String)player, comments section, footer, return - file listing -
wrapFileList(File[], Storage, long[], long[], boolean)+ sort, appendFileTableHead(),appendParentDirRow(StringBuilder, String, String, String, boolean, boolean, boolean), renderFileRow() loop, per-counter scripts; streamed when out != null and the table reaches STREAM_MIN_FILE_ROWS renderCommentsSection(Snark, boolean, boolean, boolean, String, StringBuilder), form close, lightbox/refresh scripts, footer
- Parameters:
xxxr- The Resource unusedbase- The encoded base URLparent- True if the parent directory should be includedpostParams- map of POST parameters or null if not a POSTsortParam- the file sort key from the request, or nullout- the response writer for streamed mode, or null to buffer everything into the returned string- Returns:
- buffered mode: the full page; streamed mode: the tail remaining after the last drained chunk (possibly empty); null only when postParams != null (P-R-G)
- Throws:
IOException- if the response writer or resource lookups fail
- POST dispatch - torrent actions (priorities, comments, stop/start/ recheck, edit) via
handleDirectoryPost
Dispatch a POST on the torrent directory page to its action, validating the anti-CSRF nonce first. Never renders; the caller responds with a redirect (P-R-G). A missing nonce is ignored silently; an invalid nonce or an unrecognized command adds a console message instead. Extracted from getListHTML.- Parameters:
snark- non-null target torrentpostParams- the POST parameter map, non-null
findPostAction
Returns the first matching command key from a directory-page POST, in the fixed precedence order ofDIRECTORY_POST_ACTIONS. Static and side-effect-free for testability.- Parameters:
postParams- the POST parameter map, non-null- Returns:
- the matched action key, or null if none is present
executeDirectoryPostAction
private void executeDirectoryPostAction(Snark snark, Map<String, String[]> postParams, String action) Performs the side effects of a validated directory-page POST command.- Parameters:
snark- non-null target torrentpostParams- the full POST parameter map, needed by form handlersaction- a key returned byfindPostAction(Map), non-null
renderHeader
Renders the doctype, HTML head (theme and font CSS, CSP'd theme script, favicon) and the navbar. All inputs come from servlet state so page assembly stays allocation-light; only the directory display name is passed in. Extracted from getListHTML.- Parameters:
buf- StringBuilder the markup is appended todirectory- decoded directory display name for the page title, escaped here; may be empty
appendResourceError
Renders the error table shown when the requested path within the torrent does not exist on disk. Extracted from getListHTML.- Parameters:
buf- StringBuilder the markup is appended tor- the missing resource pathbase- the encoded base URLtName- the torrent name, escaped here
appendMediaSection
private static void appendMediaSection(StringBuilder buf, String base, String tName, String mime, boolean isAudio, String imgPath) Renders the HTML5 audio/video player section for a complete single-media torrent. Static: no servlet state required beyond the parameters. Extracted from getListHTML.- Parameters:
buf- StringBuilder the markup is appended tobase- the encoded base URL with trailing slashtName- the torrent name, escaped heremime- the non-null media MIME typeisAudio- true for audio, false for videoimgPath- web-visible path to the console icons
isPaddingDir
Whether a filesystem entry is a legacy padding directory that should be hidden in top-level listings. Old versions created ".pad"/"_pad" directories. Storage no longer does, but they may still exist on disk. Extracted from getListHTML for testability.- Parameters:
f- the entry, non-null- Returns:
- true if it is a padding directory
wrapFileList
static List<Sorters.FileAndIndex> wrapFileList(File[] ls, Storage storage, long[] remainingArray, long[] previewArray, boolean skipPaddingDirs) Wraps a raw directory listing in Sorters.FileAndIndex entries carrying the precomputed per-file remaining/preview arrays, optionally hiding legacy padding directories. Pure wrapping; sorting is the caller's job. Extracted from getListHTML for testability.- Parameters:
ls- the raw listing, non-nullstorage- may be null (magnet/dummy); arrays must then be null tooremainingArray- precomputed byStorage.remaining2(), null iff storage is nullpreviewArray- may be nullskipPaddingDirs- true hides ".pad"/"_pad" directories- Returns:
- wrapped entries, possibly empty, never null
nextNameTypeSort
Next value of the name/file-type sort cycle used by the Directory column header: unset/0/1 sorts name descending ("-1"), which offers the type sort ("12"), whose reverse ("-12") restarts unsorted (""). Must stay consistent withisTypeSortNext(String). Extracted from getListHTML for testability.- Parameters:
sortParam- current sort key from the request, may be null- Returns:
- the next sort key, possibly empty, never null
isTypeSortNext
Whether the Directory column's next sort target is the file type, i.e. the current key sits in the name half ("-1"/"12") of the cycle. Drives only the link tooltip; must stay consistent withnextNameTypeSort(String).- Parameters:
sortParam- current sort key, may be null- Returns:
- true if the tooltip should advertise type sorting
appendSortToggleLink
private void appendSortToggleLink(StringBuilder buf, String base, String icon, String label, String tooltip, String nextSort, String id) Appends an icon-only column-header link that toggles to nextSort on click. Shared by all sortable columns of the file table; dedupes four identical link/icon sequences in getListHTML.- Parameters:
buf- StringBuilder the link markup is appended tobase- the encoded base URLicon- icon name (without extension)label- accessible text for the icontooltip- text for the title attributenextSort- precomputed next sort keyid- anchor id, or null for none
appendFileTableHead
private void appendFileTableHead(StringBuilder buf, String base, String directory, int dirSlash, boolean isTopLevel, boolean showSort, boolean showPriority, String sortParam) Renders the sortable column headers of the files table: Directory/ Name-type, Size, Download Status (only when priorities are shown) and Download Priority (same condition). Non-sortable state falls back to bare icons with descriptive tooltips. Extracted from getListHTML.- Parameters:
buf- target buffer, positioned inside the first <th>base- the encoded base URLdirectory- decoded directory display namedirSlash- index of '/' in directory (-1 at top level)isTopLevel- true in the torrent rootshowSort- true when more than one entry is listedshowPriority- true when priority controls are shownsortParam- current sort key, may be null
appendParentDirRow
private void appendParentDirRow(StringBuilder buf, String base, String sortParam, String decodedBase, boolean isTopLevel, boolean hasAudio, boolean showPriority) Renders the dirNav row below the column headers: the parent-directory link (subdirectories only) and the audio-playlist button when complete audio exists at or below this point. The row itself is emitted only when at least one of the two applies. The gate lives in getListHTML. hasCompleteAudio is evaluated once per view and passed in, replacing two recursive walks. Extracted from getListHTML.- Parameters:
buf- StringBuilder the markup is appended tobase- the encoded base URL with trailing slashsortParam- current sort key, may be nulldecodedBase- the decoded base URLisTopLevel- true in the torrent root (no parent link)hasAudio- result of hasCompleteAudio(fileList, ...)showPriority- true when the priority column shifts colspans
renderCommentsSection
private void renderCommentsSection(Snark snark, boolean er, boolean ec, boolean esc, String tabLabel, StringBuilder buf) Renders the collapsible comments/ratings section (opener div, toggle, tab label, body, close) when ratings or comments are enabled globally; renders nothing otherwise. Shared by both return paths of getListHTML. Previously the main path emitted stray markup outside the section and forced a comment-file load even with the feature disabled.- Parameters:
snark- non-null torrenter- ratings enabled globallyec- comments enabled globallyesc- comments enabled for this torrenttabLabel- translated label for the section tabbuf- StringBuilder the markup is appended to
prettyAnnounce
Rewrite known tracker b64 and b32 announces to their domain names for display. Literal matching only; no per-call regex compilation, and unmatched announces pass through allocation-free.- Parameters:
announce- the raw announce URL, non-null- Returns:
- the rewritten URL
appendTorrentInfo
private void appendTorrentInfo(StringBuilder buf, Snark snark, String base, String tName, boolean showStopStart) Appends detailed torrent information as HTML to the provided StringBuilder buffer.This includes torrent metadata such as torrent name, size, pieces, trackers, web seeds, completion status, download speed, share ratio, and control buttons. It handles cases where the torrent (snark) or metadata may be null.
- Parameters:
buf- the StringBuilder to append HTML tosnark- the Snark object representing the torrent; may be nullbase- the base URL or path used in linkstName- the torrent display name used in error caseshowStopStart- whether to show start/stop/recheck buttons in torrent info
appendPriority
private void appendPriority(StringBuilder buf, boolean showPriority, boolean complete, boolean isDirectory, int priority, int fileIndex) Appends the HTML markup for the file download priority options in torrent file listings. This includes radio buttons for selecting high, normal, or skip priority, conditioned on whether priority display is enabled, the file is not complete, and the file is not a directory.- Parameters:
buf- The StringBuilder to append the HTML to.showPriority- Flag indicating if priority options should be shown.complete- Flag indicating if the file download is complete.isDirectory- Flag indicating if the file is a directory.priority- The current priority value of the file (<0 is skip, 0 normal, >0 high).fileIndex- The identifier index for the file, used to ensure unique input names.
buildProgressBar
private String buildProgressBar(long total, long remaining, boolean includePercent, boolean includeTooltip, boolean noThinsp, boolean formatSize) Builds an HTML progress bar with optional percentage text and a tooltip showing the remaining size and completion percentage.- Parameters:
total- total size in bytesremaining- remaining size in bytesincludePercent- whether to include the percentage text inside the barincludeTooltip- whether to provide tooltip / value on hovernoThinsp- whether to avoid using thin spaceformatSize- whether to format the size in human-readable format- Returns:
- String containing the HTML for the progress bar
extractTorrentNameAndPath
isI2PTracker
Basic checks only, not as comprehensive as what TrackerClient does. Just to hide non-i2p trackers from the details page.- Parameters:
url- the tracker URL to classifyudpEnabled- whether i2p udp trackers count as acceptable- Returns:
- whether i2 p tracker
isAudio
Whether the MIME type is audio.- Parameters:
mime- non-null- Returns:
- true for browser-playable audio, excluding playlists
isVideo
Whether the MIME type is video.- Parameters:
mime- non-null- Returns:
- true for browser-playable video, excluding the excluded types
listFileAndIndex
private static List<Sorters.FileAndIndex> listFileAndIndex(File dir, Storage storage, long[] remainingArray) List the files in a directory and wrap each in a FileAndIndex with the given remaining array.- Parameters:
dir- the directory to liststorage- the storage for the torrentremainingArray- the precomputed remaining byte counts- Returns:
- the wrapped file list, or null if the directory cannot be listed or is empty
findCompleteFile
static String findCompleteFile(List<String> names, long[] remaining, String prefix, java.util.function.Predicate<String> match) First entry of names at or under prefix whose remaining byte count is zero and whose name satisfies match, or null. names must be index-aligned with remaining (Storage.getFileNames()paired withStorage.remaining2()). Prefix is '' at the torrent root or a directory path ending with '/' - matching is a plain startsWith across all descendant depths.- Parameters:
names- the torrent file names, index-aligned with remainingremaining- the remaining byte count of each nameprefix- '' at the torrent root, else a directory path ending with '/'match- caller-supplied name filter, e.g. the audio MIME check- Returns:
- the first matching name, or null when none qualifies
hasCompleteAudio
Whether any complete audio file exists at or below the browsed directory. Answered from Storage metadata instead of recursively listing directories on every page view.- Parameters:
storage- the torrent's storage, or null when the torrent has noneremainingArray- precomputed remaining byte counts, index-aligned with the storage file namesprefix- '' at the torrent root, else a directory path ending with '/'- Returns:
- true when at least one fully downloaded audio file matches the prefix
getPlaylist
The audio files in the resource list as an m3u playlist. https://en.wikipedia.org/wiki/M3U- Parameters:
reqURL- the encoded request URL for the browsed directory, with trailing slash, used as the base for playlist entriesbase- The encoded base URLsortParam- may be null- Returns:
- String of HTML or null if no files or on error
- Throws:
IOException- if the base URL cannot be percent-decoded
getPlaylist
private void getPlaylist(StringBuilder buf, List<Sorters.FileAndIndex> fileList, String reqURL, int sort, Storage storage, long[] remainingArray) Append playlist entries in m3u format to buf. Recursive.- Parameters:
buf- StringBuilder the m3u lines are appended tofileList- the files and subdirectories of one directoryreqURL- encoded, WITH trailing slashsort- sort key passed to Sorters.getFileComparator for subdirectory listingsstorage- the torrent's storage, for per-file remaining countsremainingArray- precomputed remaining byte counts, index-aligned with each directory listing
displayComments
Display the ratings and comments section.- Parameters:
snark- the torrent whose ratings and comments are rendereder- ratings enabled globallyec- comments enabled globallyesc- comments enabled this torrentbuf- destination for the comment table rows
renderCommentsHeader
Renders the commentInfo table header: section title plus the author-name span (the configured name, or a "configure" hint when comments are on for the torrent but no author name is set). Extracted from displayComments.- Parameters:
ctx- non-null rendering contextbuf- StringBuilder the markup is appended to
readCommentState
private static I2PSnarkServlet.CommentsHeaderResult readCommentState(CommentSet comments, boolean er, boolean ec) Reads the user's rating, community rating statistics, and the comment iterator from a torrent's comment set within a single lock scope, so markup rendering happens outside synchronized blocks. Extracted from displayComments.- Parameters:
comments- may be null when none are saved yeter- ratings enabled globallyec- comments enabled globally- Returns:
- state snapshot, never null; iter non-null only when comments exist
sortQueryString
Sort query string for torrent file-list links, where the value is a servlet-generated numeric sort key. Distinct from the request-based getQueryString() builders: no request context, and the value is HTML-stripped unconditionally rather than validated numerically.- Parameters:
so- sort key, may be null or empty for no sorting- Returns:
- "?sort=..." or ""
toIcon
suffixIcon
Icon name registered for a lower-cased path's file extension.A single map lookup replaces a scan of every registered suffix. The two forms agree because no key in
IconMaps.SUFFIX_ICON_MAPis a suffix of another, so at most one key can match and it must start at the path's last dot - exactly the substring taken here. A dotless path matches nothing either way, and a dot-leading name such as ".exe" yields itself.- Parameters:
lowerPath- the file path, already lower-cased- Returns:
- the registered icon name, or null when the extension has none
toIcon
Returns the icon name representing the file type or mime type of the given file path. Determines custom icons for certain special cases like i2p install executables.- Parameters:
path- the file path or file name to analyze- Returns:
- a string representing the icon name matching the file type
appendIcon
void appendIcon(StringBuilder buf, String name, String alt, String title, boolean fromTheme, boolean isSvg, boolean addDimensions) Appends a<img>tag for an icon to the given StringBuilder.- Parameters:
buf- the StringBuilder to append to (must not be null)name- the icon name without file extension (e.g., "magnet", "folder")alt- the alt text (should already be HTML-escaped if needed)title- the tooltip title (optional; if empty, no title attribute is added)fromTheme- if true, uses the current theme's image path (_imgPath); otherwise uses the WARBASE/icons/ pathisSvg- if true, uses .svg extension; otherwise uses .pngaddDimensions- if true, hardcodes width=16 height=16 instead of relying on CSS
appendIcon
void appendIcon(StringBuilder buf, String name, String alt, String title, boolean fromTheme, boolean isSvg) Overloaded method that defaults addDimensions to false.- Parameters:
buf- the StringBuilder to append to (must not be null)name- the icon name without file extension (e.g., "magnet", "folder")alt- the alt text (should already be HTML-escaped if needed)title- the tooltip title (optional; if empty, no title attribute is added)fromTheme- if true, uses the current theme's image path (_imgPath); otherwise uses the WARBASE/icons/ pathisSvg- if true, uses .svg extension; otherwise uses .png
toSVGWithDataTooltip
Icon file (svg) in the .war. Always 16x16. Wrapped in a tooltip span.- Parameters:
icon- name without the ".svg"altText- non-nulltitleText- non-null (used as data-tooltip)- Returns:
- the complete tooltip span with the icon image inside
savePriorities
saveComments
deleteComments
saveCommentsSetting
displayTorrentEdit
Display the edit-torrent section.- Parameters:
snark- non-nullbase- the base pathbuf- StringBuilder the edit section is appended to
saveTorrentEdit
parseEditParams
Parses the edit form POST parameters into anI2PSnarkServlet.EditParamsobject. Recognized keys: "addTracker-{id}", "removeTracker-{id}", "primary", "nofilter_newTorrentComment", "nofilter_newTorrentCreatedBy".- Parameters:
postParams- the request parameter map (Jetty-style String[] values)- Returns:
- parsed parameters, never null
warnIcon
tickIcon
Tick icon for complete files.- Returns:
- the complete img element markup, localized alt and title
priorityIcon
Priority indicator icon (block/skip, clock/normal, red clock/high).- Parameters:
priority- the file priority: negative is skipped, 0 is normal, positive is high priority- Returns:
- the indicator div with the matching icon inside
renderFileRow
private boolean renderFileRow(StringBuilder buf, I2PSnarkServlet.FileRowContext ctx, Sorters.FileAndIndex fai, boolean rowEven, I2PSnarkServlet.FileRowCounters counters) Renders a single file row for the torrent file browser table. Extracted from getListHTML for testability and UI responsiveness.- Parameters:
buf- the StringBuilder to append HTML toctx- immutable context (decoded base path, storage, priority flag, top-level flag)fai- the file and its metadata from the sorted file listrowEven- true for even row (alternating row class)counters- mutable accumulators (video/img/text counts, save button flag)- Returns:
- the next rowEven value (toggled)
hasChanges
Determines whether the edit parameters represent any actual change to the torrent's metadata. Avoids a save cycle when the form is submitted without modifications.- Parameters:
meta- current torrent MetaInfoep- parsed edit parameters- Returns:
- true if any field differs, false if identical
buildAnnounceList
static I2PSnarkServlet.AnnounceListResult buildAnnounceList(MetaInfo meta, I2PSnarkServlet.EditParams ep, List<Tracker> trackers, boolean udpEnabled) Builds the new announce list and primary tracker from the current MetaInfo and edit parameters.- Parameters:
meta- current torrent MetaInfoep- parsed edit parameterstrackers- the sorted list of known trackers (for resolving add IDs)udpEnabled- whether UDP trackers are enabled in config- Returns:
- new announce list (may be null) and primary tracker URL
noCollapsePanels
Whether the user agent cannot handle collapsible panels.- Parameters:
req- request whose user-agent header is inspected- Returns:
- true if panels should not be collapsed
isParentOf
checkNestedTorrent
Reject a torrent whose data directory lies inside another torrent's data directory, or (when checkContained) would contain another torrent's data directory. Adds a message explaining the rejection.- Parameters:
dataDir- the data directory for the torrent being added or createdcheckContained- also reject when it would contain another torrent's data- Returns:
- true to reject
isStandalone
boolean isStandalone()Whether we are running in standalone mode.- Returns:
- true if there is no router context to connect through