Skip to content

Commit 4c99294

Browse files
authored
Merge pull request #20 from Roguelazer/time3
upgrade time dependency to 0.3; use github actions instead of travis-ci
2 parents 5268460 + 486bb6b commit 4c99294

File tree

9 files changed

+140
-71
lines changed

9 files changed

+140
-71
lines changed

.github/workflows/ci.yml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [ master ]
6+
pull_request:
7+
8+
env:
9+
CARGO_TERM_COLOR: always
10+
11+
jobs:
12+
style:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v1
17+
- name: Install rust
18+
uses: actions-rs/toolchain@v1
19+
with:
20+
toolchain: stable
21+
components: rustfmt
22+
default: true
23+
- name: cargo fmt -- --check
24+
uses: actions-rs/cargo@v1
25+
with:
26+
command: fmt
27+
args: --all -- --check
28+
test:
29+
runs-on: ubuntu-latest
30+
steps:
31+
- uses: actions/checkout@v2
32+
- name: Install rust
33+
uses: actions-rs/toolchain@v1
34+
with:
35+
toolchain: stable
36+
components: rustfmt
37+
default: true
38+
- name: Test
39+
uses: actions-rs/cargo@v1
40+
with:
41+
command: test
42+
audit:
43+
runs-on: ubuntu-latest
44+
steps:
45+
- uses: actions/checkout@v2
46+
- name: Install rust
47+
uses: actions-rs/toolchain@v1
48+
with:
49+
toolchain: stable
50+
components: rustfmt
51+
default: true
52+
- name: cargo audit
53+
uses: actions-rs/[email protected]
54+
with:
55+
token: ${{ secrets.GITHUB_TOKEN }}
56+

.travis.yml

Lines changed: 0 additions & 7 deletions
This file was deleted.

CHANGES.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
NEXT
2+
------------------
3+
- Upgrade `time` dependency to 0.3 to resolve cargo audits
4+
- Switch from Travis-CI to Github Actions for CI
5+
16
0.7.0 (2020-09-24)
27
------------------
38
- Bump to Rust 2018 edition

Cargo.toml

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,16 @@ readme = "README.md"
1111
edition = "2018"
1212

1313
[dependencies]
14-
time = "^0.1"
15-
serde = { version = "1.0", optional = true }
16-
serde_derive = { version = "1.0", optional = true }
14+
time = "0.3"
15+
serde = { version = "1.0", optional = true, features=["derive"] }
1716
serde_json = { version = "1.0", optional = true }
1817
thiserror = "1.0"
1918

2019
[dev-dependencies]
21-
timeit = "0.1"
20+
timeit = { version = "0.1", git = "https://github.com/Roguelazer/timeit", rev = "9e9f2e1b9ab9537a72fc4e59ccfc1e89b5b51239" }
2221

2322
[features]
24-
serde-serialize = ["serde", "serde_derive", "serde_json"]
25-
26-
[badges]
27-
travis-ci = { repository = "Roguelazer/rust-syslog-rfc5424" }
23+
serde-serialize = ["serde", "serde_json"]
2824

2925
[package.metadata.docs.rs]
3026
all-features = true

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
This module implements an [RFC 5424](https://tools.ietf.org/html/rfc5424) IETF Syslog Protocol parser in Rust.
22

3-
[![Build Status](https://travis-ci.org/Roguelazer/rust-syslog-rfc5424.svg?branch=master)](https://travis-ci.org/Roguelazer/rust-syslog-rfc5424)
3+
[![CI](https://github.com/Roguelazer/rust-syslog-rfc5424/workflows/CI/badge.svg?branch=master)](https://github.com/Roguelazer/rust-syslog-rfc5424/actions/workflows/ci.yml)
44
[![Documentation](https://docs.rs/syslog_rfc5424/badge.svg)](https://docs.rs/syslog_rfc5424)
55
[![crates.io](https://img.shields.io/crates/v/syslog_rfc5424.svg)](https://crates.io/crates/syslog_rfc5424)
66

examples/bench.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
#[macro_use]
22
extern crate timeit;
3-
extern crate syslog_rfc5424;
4-
#[cfg(feature = "serde-serialize")]
5-
extern crate serde_json;
63

74
use syslog_rfc5424::parse_message;
85

@@ -46,6 +43,6 @@ fn main() {
4643
timeit!({
4744
parse_message(average_message).unwrap();
4845
});
49-
#[cfg(feature="serde-serialize")]
46+
#[cfg(feature = "serde-serialize")]
5047
bench_serde();
5148
}

src/lib.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,6 @@
3030
//! message. Rust doesn't have a convenient way to only treat *some* of a buffer as utf-8,
3131
//! so I'm just not supporting that. Most "real" syslog servers barf on it anway.
3232
//!
33-
#[cfg(feature = "serde-serialize")]
34-
#[macro_use]
35-
extern crate serde_derive;
36-
3733
mod facility;
3834
pub mod message;
3935
pub mod parser;

src/message.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,7 @@ impl StructuredData {
9191
}
9292

9393
/// Insert a new (sd_id, sd_param_id) -> sd_value mapping into the StructuredData
94-
pub fn insert_tuple<SI, SPI, SPV>(
95-
&mut self,
96-
sd_id: SI,
97-
sd_param_id: SPI,
98-
sd_param_value: SPV,
99-
) -> ()
94+
pub fn insert_tuple<SI, SPI, SPV>(&mut self, sd_id: SI, sd_param_id: SPI, sd_param_value: SPV)
10095
where
10196
SI: Into<SDIDType>,
10297
SPI: Into<SDParamIDType>,
@@ -151,7 +146,7 @@ pub struct SyslogMessage {
151146
pub facility: facility::SyslogFacility,
152147
pub version: i32,
153148
pub timestamp: Option<time_t>,
154-
pub timestamp_nanos: Option<i32>,
149+
pub timestamp_nanos: Option<u32>,
155150
pub hostname: Option<String>,
156151
pub appname: Option<String>,
157152
pub procid: Option<ProcId>,

src/parser.rs

Lines changed: 71 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
use std::borrow::Cow;
2+
use std::convert::TryFrom;
23
use std::num;
34
use std::str;
45
use std::str::FromStr;
5-
use std::string;
66

77
use thiserror::Error;
8-
use time;
98

109
use crate::facility;
1110
use crate::message::{ProcId, StructuredData, SyslogMessage};
@@ -30,13 +29,19 @@ pub enum ParseErr {
3029
#[error("unicode error: {0}")]
3130
BaseUnicodeError(#[from] str::Utf8Error),
3231
#[error("unicode error: {0}")]
33-
UnicodeError(#[from] string::FromUtf8Error),
32+
UnicodeError(#[from] std::string::FromUtf8Error),
3433
#[error("unexpected input at character {0}")]
3534
ExpectedTokenErr(char),
3635
#[error("integer conversion error: {0}")]
3736
IntConversionErr(#[from] num::ParseIntError),
3837
#[error("missing field {0}")]
3938
MissingField(&'static str),
39+
#[error("invalid month number {0}")]
40+
InvalidMonth(u8),
41+
#[error("date had invalid field {0}")]
42+
InvalidDate(String),
43+
#[error("date had invalid UTC offset")]
44+
InvalidOffset,
4045
}
4146

4247
// We parse with this super-duper-dinky hand-coded recursive descent parser because we don't really
@@ -182,8 +187,8 @@ fn parse_sde(sde: &str) -> ParseResult<((String, ParsedSDParams), &str)> {
182187

183188
fn parse_sd(structured_data_raw: &str) -> ParseResult<(StructuredData, &str)> {
184189
let mut sd = StructuredData::new_empty();
185-
if structured_data_raw.starts_with('-') {
186-
return Ok((sd, &structured_data_raw[1..]));
190+
if let Some(rest) = structured_data_raw.strip_prefix('-') {
191+
return Ok((sd, rest));
187192
}
188193
let mut rest = structured_data_raw;
189194
while !rest.is_empty() {
@@ -204,8 +209,9 @@ fn parse_pri_val(pri: i32) -> ParseResult<(severity::SyslogSeverity, facility::S
204209
Ok((sev, fac))
205210
}
206211

212+
/// Parse an i32
207213
fn parse_num(s: &str, min_digits: usize, max_digits: usize) -> ParseResult<(i32, &str)> {
208-
let (res, rest1) = take_while(s, |c| c >= '0' && c <= '9', max_digits);
214+
let (res, rest1) = take_while(s, |c| ('0'..='9').contains(&c), max_digits);
209215
let rest = rest1.ok_or(ParseErr::UnexpectedEndOfInput)?;
210216
if res.len() < min_digits {
211217
Err(ParseErr::TooFewDigits)
@@ -219,6 +225,22 @@ fn parse_num(s: &str, min_digits: usize, max_digits: usize) -> ParseResult<(i32,
219225
}
220226
}
221227

228+
/// Parse an i32
229+
fn parse_num_generic<NT>(s: &str, min_digits: usize, max_digits: usize) -> ParseResult<(NT, &str)>
230+
where
231+
NT: FromStr<Err = num::ParseIntError>,
232+
{
233+
let (res, rest1) = take_while(s, |c| ('0'..='9').contains(&c), max_digits);
234+
let rest = rest1.ok_or(ParseErr::UnexpectedEndOfInput)?;
235+
if res.len() < min_digits {
236+
Err(ParseErr::TooFewDigits)
237+
} else if res.len() > max_digits {
238+
Err(ParseErr::TooManyDigits)
239+
} else {
240+
Ok((NT::from_str(res).map_err(ParseErr::IntConversionErr)?, rest))
241+
}
242+
}
243+
222244
fn parse_decimal(d: &str, min_digits: usize, max_digits: usize) -> ParseResult<(i32, &str)> {
223245
parse_num(d, min_digits, max_digits).map(|(val, s)| {
224246
let mut multiplicand = 1;
@@ -231,52 +253,65 @@ fn parse_decimal(d: &str, min_digits: usize, max_digits: usize) -> ParseResult<(
231253
})
232254
}
233255

234-
fn parse_timestamp(m: &str) -> ParseResult<(Option<time::Timespec>, &str)> {
256+
fn parse_timestamp(m: &str) -> ParseResult<(Option<time::OffsetDateTime>, &str)> {
235257
let mut rest = m;
236-
if rest.starts_with('-') {
237-
return Ok((None, &rest[1..]));
258+
if let Some(rest) = rest.strip_prefix('-') {
259+
return Ok((None, rest));
238260
}
239-
let mut tm = time::empty_tm();
240-
tm.tm_year = take_item!(parse_num(rest, 4, 4), rest) - 1900;
261+
let year = take_item!(parse_num(rest, 4, 4), rest);
241262
take_char!(rest, '-');
242-
tm.tm_mon = take_item!(parse_num(rest, 2, 2), rest) - 1;
263+
let month_num = take_item!(parse_num_generic(rest, 2, 2), rest);
264+
let month = time::Month::try_from(month_num).map_err(|_| ParseErr::InvalidMonth(month_num))?;
243265
take_char!(rest, '-');
244-
tm.tm_mday = take_item!(parse_num(rest, 2, 2), rest);
266+
let mday = take_item!(parse_num_generic(rest, 2, 2), rest);
267+
let date = time::Date::from_calendar_date(year, month, mday)
268+
.map_err(|e| ParseErr::InvalidDate(e.name().to_string()))?;
245269
take_char!(rest, 'T');
246-
tm.tm_hour = take_item!(parse_num(rest, 2, 2), rest);
270+
let hour = take_item!(parse_num_generic(rest, 2, 2), rest);
247271
take_char!(rest, ':');
248-
tm.tm_min = take_item!(parse_num(rest, 2, 2), rest);
272+
let minute = take_item!(parse_num_generic(rest, 2, 2), rest);
249273
take_char!(rest, ':');
250-
tm.tm_sec = take_item!(parse_num(rest, 2, 2), rest);
251-
if rest.starts_with('.') {
274+
let second = take_item!(parse_num_generic(rest, 2, 2), rest);
275+
let nano = if rest.starts_with('.') {
252276
take_char!(rest, '.');
253-
tm.tm_nsec = take_item!(parse_decimal(rest, 1, 6), rest);
254-
}
277+
take_item!(parse_decimal(rest, 1, 6), rest) as u32
278+
} else {
279+
0
280+
};
281+
let time = time::Time::from_hms_nano(hour, minute, second, nano)
282+
.map_err(|e| ParseErr::InvalidDate(e.name().to_string()))?;
255283
// Tm::utcoff is totally broken, don't use it.
256-
let utc_offset_mins = match rest.chars().next() {
257-
None => 0,
284+
let utc_offset = match rest.chars().next() {
285+
None => None,
258286
Some('Z') => {
259287
rest = &rest[1..];
260-
0
288+
None
261289
}
262290
Some(c) => {
263291
let (sign, irest) = match c {
264292
// Note: signs are backwards as per RFC3339
265-
'-' => (1, &rest[1..]),
266-
'+' => (-1, &rest[1..]),
293+
'-' => (-1, &rest[1..]),
294+
'+' => (1, &rest[1..]),
267295
_ => {
268296
return Err(ParseErr::InvalidUTCOffset);
269297
}
270298
};
271-
let hours = i32::from_str(&irest[0..2]).map_err(ParseErr::IntConversionErr)?;
272-
let minutes = i32::from_str(&irest[3..5]).map_err(ParseErr::IntConversionErr)?;
299+
let hours = i8::from_str(&irest[0..2]).map_err(ParseErr::IntConversionErr)?;
300+
let minutes = i8::from_str(&irest[3..5]).map_err(ParseErr::IntConversionErr)?;
273301
rest = &irest[5..];
274-
minutes * sign + hours * 60 * sign
302+
Some(
303+
time::UtcOffset::from_hms(hours * sign, minutes * sign, 0)
304+
.map_err(|_| ParseErr::InvalidOffset)?,
305+
)
275306
}
276307
};
277-
tm = tm + time::Duration::minutes(i64::from(utc_offset_mins));
278-
tm.tm_isdst = -1;
279-
Ok((Some(tm.to_utc().to_timespec()), rest))
308+
let naive_dt = time::PrimitiveDateTime::new(date, time);
309+
let dt = if let Some(utc_offset) = utc_offset {
310+
naive_dt.assume_offset(utc_offset)
311+
} else {
312+
naive_dt.assume_utc()
313+
};
314+
Ok((Some(dt), rest))
280315
}
281316

282317
fn parse_term(
@@ -318,14 +353,10 @@ fn parse_message_s(m: &str) -> ParseResult<SyslogMessage> {
318353
take_char!(rest, ' ');
319354
let appname = take_item!(parse_term(rest, 1, 48), rest);
320355
take_char!(rest, ' ');
321-
let procid_r = take_item!(parse_term(rest, 1, 128), rest);
322-
let procid = match procid_r {
323-
None => None,
324-
Some(s) => Some(match i32::from_str(&s) {
325-
Ok(n) => ProcId::PID(n),
326-
Err(_) => ProcId::Name(s),
327-
}),
328-
};
356+
let procid = take_item!(parse_term(rest, 1, 128), rest).map(|s| match i32::from_str(&s) {
357+
Ok(n) => ProcId::PID(n),
358+
Err(_) => ProcId::Name(s),
359+
});
329360
take_char!(rest, ' ');
330361
let msgid = take_item!(parse_term(rest, 1, 32), rest);
331362
take_char!(rest, ' ');
@@ -340,8 +371,8 @@ fn parse_message_s(m: &str) -> ParseResult<SyslogMessage> {
340371
severity: sev,
341372
facility: fac,
342373
version,
343-
timestamp: event_time.map(|t| t.sec),
344-
timestamp_nanos: event_time.map(|t| t.nsec),
374+
timestamp: event_time.map(|t| t.unix_timestamp()),
375+
timestamp_nanos: event_time.map(|t| t.time().nanosecond()),
345376
hostname,
346377
appname,
347378
procid,

0 commit comments

Comments
 (0)