diff options
author | Emiliano Ciavatta | 2020-10-19 14:20:53 +0000 |
---|---|---|
committer | Emiliano Ciavatta | 2020-10-19 14:20:53 +0000 |
commit | 6b30ace7f6919d5e5122959d0abf463906fa17d7 (patch) | |
tree | d1bb3cb3ef5efe939de996be8af9b768719f36f6 /frontend/src | |
parent | 0e82d50eb37c87ecd5a75cf842c4da8f7047e5dc (diff) |
Highlight rules in stream pane
Diffstat (limited to 'frontend/src')
-rw-r--r-- | frontend/src/components/panels/StreamsPane.js | 40 | ||||
-rw-r--r-- | frontend/src/components/panels/StreamsPane.scss | 6 | ||||
-rw-r--r-- | frontend/src/model/rules.js | 43 |
3 files changed, 81 insertions, 8 deletions
diff --git a/frontend/src/components/panels/StreamsPane.js b/frontend/src/components/panels/StreamsPane.js index 9470d7d..cc3d53a 100644 --- a/frontend/src/components/panels/StreamsPane.js +++ b/frontend/src/components/panels/StreamsPane.js @@ -21,12 +21,14 @@ import {Row} from "react-bootstrap"; import ReactJson from "react-json-view"; import backend from "../../backend"; import log from "../../log"; +import rules from "../../model/rules"; import {downloadBlob, getHeaderValue} from "../../utils"; import ButtonField from "../fields/ButtonField"; import ChoiceField from "../fields/ChoiceField"; import MessageAction from "../objects/MessageAction"; import "./StreamsPane.scss"; +const reactStringReplace = require('react-string-replace') const classNames = require("classnames"); class StreamsPane extends Component { @@ -77,11 +79,9 @@ class StreamsPane extends Component { }; tryParseConnectionMessage = (connectionMessage) => { + const isClient = connectionMessage["from_client"]; if (connectionMessage.metadata == null) { - return connectionMessage.content; - } - if (connectionMessage["is_metadata_continuation"]) { - return <span style={{"fontSize": "12px"}}>**already parsed in previous messages**</span>; + return this.highlightRules(connectionMessage.content, isClient); } let unrollMap = (obj) => obj == null ? null : Object.entries(obj).map(([key, value]) => @@ -96,7 +96,7 @@ class StreamsPane extends Component { return <span className="type-http-request"> <p style={{"marginBottom": "7px"}}><strong>{m.method}</strong> {url} {m.protocol}</p> {unrollMap(m.headers)} - <div style={{"margin": "20px 0"}}>{m.body}</div> + <div style={{"margin": "20px 0"}}>{this.highlightRules(m.body, isClient)}</div> {unrollMap(m.trailers)} </span>; case "http-response": @@ -108,20 +108,44 @@ class StreamsPane extends Component { body = <ReactJson src={json} theme="grayscale" collapsed={false} displayDataTypes={false}/>; } catch (e) { log.error(e); + body = m.body; } } return <span className="type-http-response"> <p style={{"marginBottom": "7px"}}>{m.protocol} <strong>{m.status}</strong></p> {unrollMap(m.headers)} - <div style={{"margin": "20px 0"}}>{body}</div> + <div style={{"margin": "20px 0"}}>{this.highlightRules(body, isClient)}</div> {unrollMap(m.trailers)} </span>; default: - return connectionMessage.content; + return this.highlightRules(connectionMessage.content, isClient); } }; + highlightRules = (content, isClient) => { + let streamContent = content; + this.props.connection["matched_rules"].forEach(ruleId => { + const rule = rules.ruleById(ruleId); + rule.patterns.forEach(pattern => { + if ((!isClient && pattern.direction === 1) || (isClient && pattern.direction === 2)) { + return; + } + let flags = ""; + pattern["caseless"] && (flags += "i"); + pattern["dot_all"] && (flags += "s"); + pattern["multi_line"] && (flags += "m"); + pattern["unicode_property"] && (flags += "u"); + const regex = new RegExp("(" + pattern.regex + ")", flags); + streamContent = reactStringReplace(streamContent, regex, (match, i) => ( + <span key={i} className="matched-occurrence" style={{"backgroundColor": rule.color}}>{match}</span> + )); + }); + }); + + return streamContent; + }; + connectionsActions = (connectionMessage) => { if (!connectionMessage.metadata) { return null; @@ -187,7 +211,7 @@ class StreamsPane extends Component { }; const content = this.state.messages || []; - let payload = content.map((c, i) => + let payload = content.filter((c) => !c["is_metadata_continuation"]).map((c, i) => <div key={`content-${i}`} className={classNames("connection-message", c["from_client"] ? "from-client" : "from-server")}> <div className="connection-message-header container-fluid"> diff --git a/frontend/src/components/panels/StreamsPane.scss b/frontend/src/components/panels/StreamsPane.scss index 1d8a250..c44c7eb 100644 --- a/frontend/src/components/panels/StreamsPane.scss +++ b/frontend/src/components/panels/StreamsPane.scss @@ -18,6 +18,12 @@ &:hover::-webkit-scrollbar-thumb { background: $color-secondary-2; } + + .matched-occurrence { + color: $color-primary-4; + font-weight: 500; + border-radius: 2px; + } } .connection-message { diff --git a/frontend/src/model/rules.js b/frontend/src/model/rules.js new file mode 100644 index 0000000..625d610 --- /dev/null +++ b/frontend/src/model/rules.js @@ -0,0 +1,43 @@ +/* + * This file is part of caronte (https://github.com/eciavatta/caronte). + * Copyright (c) 2020 Emiliano Ciavatta. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +import backend from "../backend"; +import log from "../log"; + +const _ = require("lodash"); + +class Rules { + + constructor() { + this.rules = []; + this.loadRules(); + } + + loadRules = () => { + backend.get("/api/rules").then((res) => this.rules = res.json) + .catch((err) => log.error("Failed to load rules", err)); + }; + + allRules = () => _.clone(this.rules); + + ruleById = (id) => _.clone(this.rules.find(r => r.id === id)); + +} + +const rules = new Rules(); + +export default rules; |