diff --git a/reader.go b/reader.go index b19324eb..d28dd2f0 100644 --- a/reader.go +++ b/reader.go @@ -26,8 +26,8 @@ var reKeyValue = regexp.MustCompile(`([a-zA-Z0-9_-]+)=("[^"]+"|[^",]+)`) // TimeParse allows globally apply and/or override Time Parser function. // Available variants: -// * FullTimeParse - implements full featured ISO/IEC 8601:2004 -// * StrictTimeParse - implements only RFC3339 Nanoseconds format +// - FullTimeParse - implements full featured ISO/IEC 8601:2004 +// - StrictTimeParse - implements only RFC3339 Nanoseconds format var TimeParse func(value string) (time.Time, error) = FullTimeParse // Decode parses a master playlist passed from the buffer. If `strict` @@ -536,7 +536,9 @@ func decodeLineOfMediaPlaylist(p *MediaPlaylist, wv *WV, state *decodingState, l } // If EXT-X-KEY appeared before reference to segment (EXTINF) then it linked to this segment if state.tagKey { - p.Segments[p.last()].Key = &Key{state.xkey.Method, state.xkey.URI, state.xkey.IV, state.xkey.Keyformat, state.xkey.Keyformatversions} + if segment := p.Segments[p.last()]; segment != nil { + segment.Key = &Key{state.xkey.Method, state.xkey.URI, state.xkey.IV, state.xkey.Keyformat, state.xkey.Keyformatversions} + } // First EXT-X-KEY may appeared in the header of the playlist and linked to first segment // but for convenient playlist generation it also linked as default playlist key if p.Key == nil { @@ -546,7 +548,9 @@ func decodeLineOfMediaPlaylist(p *MediaPlaylist, wv *WV, state *decodingState, l } // If EXT-X-MAP appeared before reference to segment (EXTINF) then it linked to this segment if state.tagMap { - p.Segments[p.last()].Map = &Map{state.xmap.URI, state.xmap.Limit, state.xmap.Offset} + if segment := p.Segments[p.last()]; segment != nil { + segment.Map = &Map{state.xmap.URI, state.xmap.Limit, state.xmap.Offset} + } // First EXT-X-MAP may appeared in the header of the playlist and linked to first segment // but for convenient playlist generation it also linked as default playlist map if p.Map == nil { @@ -557,7 +561,9 @@ func decodeLineOfMediaPlaylist(p *MediaPlaylist, wv *WV, state *decodingState, l // if segment custom tag appeared before EXTINF then it links to this segment if state.tagCustom { - p.Segments[p.last()].Custom = state.custom + if segment := p.Segments[p.last()]; segment != nil { + segment.Custom = state.custom + } state.custom = make(map[string]CustomTag) state.tagCustom = false } @@ -759,7 +765,7 @@ func decodeLineOfMediaPlaylist(p *MediaPlaylist, wv *WV, state *decodingState, l if err == nil { state.tagWV = true } - case strings.HasPrefix(line, "#WV-CYPHER-VERSION"): + case strings.HasPrefix(line, "#WV-CYPHER-VERSION "): state.listType = MEDIA wv.CypherVersion = line[19:] state.tagWV = true @@ -803,7 +809,7 @@ func decodeLineOfMediaPlaylist(p *MediaPlaylist, wv *WV, state *decodingState, l if err == nil { state.tagWV = true } - case strings.HasPrefix(line, "#WV-VIDEO-RESOLUTION"): + case strings.HasPrefix(line, "#WV-VIDEO-RESOLUTION "): state.listType = MEDIA wv.VideoResolution = line[21:] state.tagWV = true diff --git a/reader_test.go b/reader_test.go index 8d60b16c..d5c520e2 100644 --- a/reader_test.go +++ b/reader_test.go @@ -1,11 +1,11 @@ /* - Playlist parsing tests. +Playlist parsing tests. - Copyright 2013-2019 The Project Developers. - See the AUTHORS and LICENSE files at the top-level directory of this distribution - and at https://github.com/grafov/m3u8/ +Copyright 2013-2019 The Project Developers. +See the AUTHORS and LICENSE files at the top-level directory of this distribution +and at https://github.com/grafov/m3u8/ - ॐ तारे तुत्तारे तुरे स्व +ॐ तारे तुत्तारे तुरे स्व */ package m3u8 @@ -972,6 +972,113 @@ func TestDecodeMediaPlaylistStartTime(t *testing.T) { } } +/******************** + * Bad data tests * + ********************/ + +// Test mallformed playlist +func TestMalformedMasterPlaylis(t *testing.T) { + data := []byte("#EXT-X-START:\n#EXTM3U") + _, _, err := DecodeFrom(bytes.NewReader(data), true) + if err != nil { + if !errors.Is(err, ErrorNoEXTM3U) { + t.Errorf("Wrong error type at DecodeFrom: %s", err) + } + } else { + t.Error("No error on malformed playlist on DecodeFrome") + } + if _, _, err := DecodeFrom(bytes.NewReader(data), false); err != nil { + t.Errorf("Unexpected error on not strict mode of parsing: %s", err) + } + + var master = new(MasterPlaylist) + err = master.DecodeFrom(bytes.NewReader(data), true) + if err != nil { + if !errors.Is(err, ErrorNoEXTM3U) { + t.Errorf("Wrong error type at (*MasterPlaylist).DecodeFrom: %s", + err) + } + } else { + t.Error("No error on malformed playlist on (*MasterPlaylist).DecodeFrome") + } + + if err := master.DecodeFrom(bytes.NewReader(data), false); err != nil { + t.Errorf("Unexpected error on not strict mode of parsing: %s", err) + } + + var media = new(MediaPlaylist) + err = media.DecodeFrom(bytes.NewReader(data), true) + if err != nil { + if !errors.Is(err, ErrorNoEXTM3U) { + t.Errorf("Wrong error type at (*MediaPlaylist).DecodeFrom: %s", + err) + } + } else { + // TODO: There is probably an error here. The + // tag EXT-X-START should only appear in the master playlist. + t.Error("No error on malformed playlist on (*MediaPlaylist).DecodeFrome") + } + if err := media.DecodeFrom(bytes.NewReader(data), false); err != nil { + t.Errorf("Unexpected error on not strict mode of parsing: %s", err) + } + +} + +func TestDecodeMediaPlaylistDicontinuityAtBegin(t *testing.T) { + f, err := os.Open("sample-playlists/media-with-discontinuity-at-start.m3u8") + if err != nil { + t.Fatal(err) + } + p, listType, err := DecodeFrom(bufio.NewReader(f), true) + if err != nil { + t.Fatal(err) + } + pp := p.(*MediaPlaylist) + CheckType(t, pp) + if listType != MEDIA { + t.Error("Sample not recognized as media playlist.") + } + if pp.StartTime != float64(0.0) { + t.Errorf("Media segment StartTime != 0: %f", pp.StartTime) + } +} + +// Test for https://github.com/khenarghot/m3u8/issues/3 +func TestMellformedPanicIssue3(t *testing.T) { + bad := bytes.NewBuffer([]byte(`#WV-CYPHER-VERSION`)) + _, _, err := DecodeFrom(bad, true) + if err == nil { + t.Fail() + } +} + +// Test for https://github.com/khenarghot/m3u8/issues/1 +func TestMellformedPanicIssue1(t *testing.T) { + bad := bytes.NewBuffer([]byte(`#WV-VIDEO-RESOLUTION`)) + _, _, err := DecodeFrom(bad, true) + if err == nil { + t.Fail() + } +} + +// Test for https://github.com/khenarghot/m3u8/issues/2 +func TestMellformedPanicIssue2(t *testing.T) { + bad := bytes.NewBuffer([]byte("#EXT-X-KEY:\n0")) + _, _, err := DecodeFrom(bad, false) + if err != nil { + t.Fail() + } +} + +// Test for https://github.com/khenarghot/m3u8/issues/2 +func TestMellformedPanicIssue2AltMAP(t *testing.T) { + bad := bytes.NewBuffer([]byte("#EXT-X-MAP:\n0")) + _, _, err := DecodeFrom(bad, false) + if err != nil { + t.Fail() + } +} + /**************** * Benchmarks * ****************/